﻿/*************************************************************************************
 *
 * 文 件 名：  Worker
 * 描    述：  告警
 * 
 * 版    本：  V1.0
 * 创 建 者：  YSW
 * 创建时间：  2021-12-24 15:11:48
 * ======================================
 * 历史更新记录
 * 版本：V          修改时间：         修改人：
 * 修改内容：
 * ======================================
*************************************************************************************/

using CommonModel.Util;
using Dm;
using GXRTBTC.PublicClassLibrary;
using GXRTBTC.PublicClassLibrary.Model;
using GXRTBTC.PublicClassLibrary.Util;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Npgsql;
using RedisHelp;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace GXRTBTC.AlarmMergeService
{
    /// <summary>
    /// 后台服务
    /// </summary>
    public class Worker : BackgroundService
    {
//        #region 参数
//        /// <summary>
//        /// 当前节点名称
//        /// 组成：节点所在IP+容器ID
//        /// </summary>
//        //public string nodeName { get; set; } = TransForm.GetContainerAddress() + "_" + Environment.MachineName;
//        public string nodeName { get; set; } = TransForm.GetHostIPOrName() + "_" + Environment.MachineName;
//        /// <summary>
//        /// 日志
//        /// </summary>
//        private readonly ILogger mLogger;
//        /// <summary>
//        /// 配置
//        /// </summary>
//        private readonly IConfiguration mConfiguration;
//        //当前节点ID 即UUID
//        //private string uuid { get; set; } = System.Guid.NewGuid().ToString("N");
//        /// <summary>
//        /// StackExchange.Redis
//        /// </summary>
//        private RedisHelper redisInit { get; set; }
//        private string redisConnString { get; set; }

//        /// <summary>
//        /// 副本数，默认只有自身
//        /// </summary>
//        private int nodeNum { get; set; } = 1;
//        /// <summary>
//        /// 当前副本编号
//        /// </summary>
//        private int nodeNo { get; set; } = 0;
//        /// <summary>
//        /// AI地数图像识别，节目最新时间和当前时间间隔，暂定阈值10分钟，超过为无效数据（不告警）
//        /// </summary>
//        private int AILatestMinuteGap { get; set; } = 10;
//        /// <summary>
//        /// 告警开始防抖动时间
//        /// </summary>
//        private int alarmTime { get; set; } = 5;
//        /// <summary>
//        /// 告警结束防抖动时间
//        /// </summary>
//        private int alarmEndTime { get; set; } = 3;
//        /// <summary>
//        /// AI地数图像识别，节目错误开始时间和当前时间间隔，暂定阈值2分钟，小于则认为无效（不告警）
//        /// 对应关系静帧、马赛克、黑场、无伴音，值分别默认为3,5,0,5
//        /// 黑场：0分钟、静帧：3分钟、马赛克、无半音：5分钟
//        /// </summary>
//        private int[] AIErrStartMinuteGap { get; set; } = new int[] { 3, 5, 0, 5 };
//        /// <summary>
//        /// 分配到任务数 当前副本需要处理的台站数
//        /// </summary>
//        private int[] taskNum { get; set; }
//        /// <summary>
//        /// 1~3级台站调频、中波提前开机默认值
//        /// </summary>
//        private int defaltAddMinutes { get; set; } = 25;
//        /// <summary>
//        /// 1~3级台站调频、中波提前开机、延时关机数据
//        /// </summary>
//        private Dictionary<string, Dictionary<string, Dictionary<string, string>>> timeAdvanceAndDelayInfo { get; set; } = new();

//        /// <summary>
//        /// 实时告警处理线程数量 建议不超过10个的奇数
//        /// 除了依靠节点数，这里还续支持多个线程，增加处理能力
//        /// </summary>
//#if DEBUG
//        private int threadNum { get; set; } = 1;
//#else
//        private int threadNum { get; set; } = 8;
//#endif
//        /// <summary>
//        /// kafka生产者池
//        /// </summary>
//        private ProducerPool mProducerPool { get; set; }
//        /// <summary>
//        /// 存在涛思数据库中
//        /// 告警历史表
//        /// </summary>
//        //private string alarmHisTableName { get; set; } = "alarm_data_his";
//        private string alarmHisPrefix { get; set; } = "alarm_his_";
//        private string alarmHisTableColumn { get; set; } = "ts,alarm_key,isintime,alarm,clear,get_time,upd_time,parentalarm_key,alarm_code,alarm_name,alarm_title,alarm_desc,alarm_level,alarm_value,alarm_id,alarm_type,station_id,station_name,station_level,subcenter_id,position_id,frequency,sub_system_id,device_type_id,program_name,program_summary,program_level,device_type,alarm_duration,schemaName,parno,parno_alias,alarm_locate";

//        /// <summary>
//        /// 所有台站
//        /// </summary>
//        private Dictionary<string, Dictionary<string, string>> stationsInfo { get; set; } = new Dictionary<string, Dictionary<string, string>>();
//        /// <summary>
//        /// 台站处理标志，是否正在处理
//        /// </summary>
//        private Dictionary<string, bool> dealStation { get; set; } = new Dictionary<string, bool>();
//        /// <summary>
//        /// 所有在用台站
//        /// </summary>
//        //private List<string> stations { get; set; } = new List<string>();
//        /// <summary>
//        /// 台站时间表信息
//        /// </summary>
//        private Dictionary<string, Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>> timesTables { get; set; } = new Dictionary<string, Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>>();
//        /// <summary>
//        /// 实时告警模型
//        /// </summary>
//        //private Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>> realAlarmModel { get; set; } = new Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>>();
//        private Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>> realAlarmInfo { get; set; } = new Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>>();
//        /// <summary>
//        /// 模型信息
//        /// </summary>
//        private Dictionary<string, Dictionary<string, Dictionary<string, string>>> alarmDataModel { get; set; } = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();

//        /// <summary>
//        /// 告警提示音设置信息
//        /// </summary>
//        private Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> alarmSets { get; set; } = new();

//        /// <summary>
//        /// 所有告警唯一key，用于定时更新数据库
//        /// </summary>
//        private Dictionary<string, bool> updateAlarmCodes { get; set; } = new();

//        /// <summary>
//        /// 告警级别提升规则
//        /// </summary>
//        private Dictionary<string, AlarmRules> alarmRuleInfos { get; set; } = new();

//        /// <summary>
//        /// 特殊告警模板信息
//        /// 有些台站设备需要设置特殊告警设置的，在这里体现
//        /// </summary>
//        private Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>> modelManagement { get; set; } = new();

//        /// <summary>
//        /// 节目信息
//        /// </summary>
//        private Dictionary<string, Dictionary<string, string>> programInfo { get; set; } = new Dictionary<string, Dictionary<string, string>>();
//        /// <summary>
//        /// 节目SID对应节目号
//        /// </summary>
//        private Dictionary<string, string> sid2ProgramInfo { get; set; } = new Dictionary<string, string>();
//        /// <summary>
//        /// 台站频率匹配节目信息关系
//        /// </summary>
//        private Dictionary<string, Dictionary<string, Dictionary<string, string>>> stationFrqAndProgram { get; set; } = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
//        /// <summary>
//        /// 节目停播记录
//        /// </summary>
//        private Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>> broadcastTimeSet { get; set; } = new();
//        /// <summary>
//        /// 是否启用标志，用bit表示
//        /// 月末停播标识
//        /// 0关闭 00
//        /// 1只启动参数1，每月倒数第一周 01
//        /// 2只启动参数2，每月倒数第二周 10
//        /// 3参数1、2都启用 11
//        /// </summary>
//        private char[] loopAlarmFlags { get; set; } = new char[] { '1', '1' };
//        /// <summary>
//        /// 月末第一、第二个周二停播时间段
//        /// </summary>
//        private LoopAlarmTime loopAlarmTime { get; set; } = new();
//        /// <summary>
//        /// 关联、衍生告警告警模型
//        /// </summary>
//        private List<Dictionary<string, Object>> relationAlarmInfos { get; set; } = new List<Dictionary<string, object>>();

//        /// <summary>
//        /// 对象锁，用于线程间同步gapNums
//        /// </summary>
//        public Object syncLock { get; } = new object();

//        /// <summary>
//        /// 轮询告警一次用时
//        /// </summary>
//        private long loopOnceTime { get; set; } = 0;
//        /// <summary>
//        /// 针对有些告警，有告警时上报，无告警时不上报的情况，无上报超时秒数，超时后默认告警正常
//        /// </summary>
//        private int alarmTimeout { get; set; } = 15;

//        /// <summary>
//        /// pgsql
//        /// </summary>
//        private DbConnection dbConnection { get; set; }
//        /// <summary>
//        /// 数据库是否连接
//        /// </summary>
//        private bool IsDbConn { get; set; } = false;

//        /// <summary>
//        /// 最小线程池数量
//        /// </summary>
//        private int minPoolNum { get; set; } = 400;
//        /// <summary>
//        /// 最大线程池数量
//        /// </summary>
//        private int maxPoolNum { get; set; } = 500;

//        private long timeOutNum { get; set; } = 0;
//        /// <summary>
//        /// 记录台站轮询告警是否结束标志
//        /// </summary>
//        private Dictionary<string, bool> stationTask { get; set; } = new Dictionary<string, bool>();
//        /// <summary>
//        /// 台站设备is_enable情况临时缓存汇总
//        /// </summary>
//        private Dictionary<string, Dictionary<string, int>> stationDevIsEnables { get; set; } = new();

//        /// <summary>
//        /// 当前节点状态统计信息
//        /// </summary>
//        private Dictionary<string, Object> nodeStatusInfo { get; set; } = new Dictionary<string, object>() {
//            { "Datetime", TransForm.GetFormatDatetime() },
//            { "StationNum", 0 },
//            { "LoopTime",0 },
//            { "nodeNo",0 }
//        };

//        /// <summary>
//        /// 配置集
//        /// </summary>
//        private Dictionary<string, string> paramInfo { get; set; } = new();
//        #endregion

//        /// <summary>
//        /// 构造函数
//        /// </summary>
//        /// <param name="logger"></param>
//        /// <param name="configuration"></param>
//        public Worker(ILogger<Worker> logger, IConfiguration configuration)
//        {
//            this.mLogger = logger;
//            this.mConfiguration = configuration;

//            //给通用日志赋值
//            CommonUtil.mLogger = logger;

//            Init();
//        }

//        #region 初始化
//        /// <summary>
//        /// 初始化
//        /// </summary>
//        private void Init()
//        {
//            mLogger.LogInformation("初始化 。。。");

//            try
//            {
//                //redis初始化
//                redisConnString = RsaEncrypt.DecryptFree(mConfiguration["RedisConnString"]);
//#if DEBUG
//                redisConnString = RsaEncrypt.DecryptFree(mConfiguration["RedisConnStringDebug"]);
//#endif
//                mLogger.LogInformation(redisConnString);
//                redisInit = new RedisHelper(redisConnString, mLogger);
//            }
//            catch { }

//            //从缓存读取设置
//            paramInfo = redisInit.HashGetAllDict<string>("paramInfo");
//            taskNum = new int[threadNum];

//            //设置线程池
//            ThreadPool.SetMinThreads(minPoolNum, minPoolNum);
//            ThreadPool.SetMaxThreads(maxPoolNum, maxPoolNum);

//            defaltAddMinutes = int.Parse(paramInfo.GetValueOrDefault("defaltAddMinutes", "25"));
//            alarmTimeout = paramInfo.ContainsKey("alarm.timeout") ? int.Parse(paramInfo.GetValueOrDefault("alarm.timeout", "15")) : alarmTimeout;

//            string tmpAlarmTime = paramInfo.GetValueOrDefault("AlarmTime", "4");
//            string tmpAlarmEndTime = paramInfo.GetValueOrDefault("AlarmEndTime", "3");
//            string aILatestMinuteGap = paramInfo.GetValueOrDefault("AILatestMinuteGap", "10");
//            string aIErrStartMinuteGap = paramInfo.GetValueOrDefault("AIErrStartMinuteGap", "3,5,0,5");

//            //告警开始防抖动时间
//            //if (mConfiguration["AlarmTime"] != null && !"".Equals(mConfiguration["AlarmTime"]) && TransForm.IsInt(mConfiguration["AlarmTime"]))
//            if (tmpAlarmTime != null && !"".Equals(tmpAlarmTime) && TransForm.IsInt(tmpAlarmTime))
//            {
//                //alarmTime = int.Parse(mConfiguration["AlarmTime"]);
//                alarmTime = int.Parse(tmpAlarmTime);
//            }
//            //告警结束防抖动时间
//            //if (mConfiguration["AlarmEndTime"] != null && !"".Equals(mConfiguration["AlarmEndTime"]) && TransForm.IsInt(mConfiguration["AlarmEndTime"]))
//            if (tmpAlarmEndTime != null && !"".Equals(tmpAlarmEndTime) && TransForm.IsInt(tmpAlarmEndTime))
//            {
//                //alarmEndTime = int.Parse(mConfiguration["AlarmEndTime"]);
//                alarmEndTime = int.Parse(tmpAlarmEndTime);
//            }
//            //AI地数图像识别，节目最新时间和当前时间间隔，暂定阈值10分钟，超过为无效数据（不告警）
//            //if (mConfiguration["AILatestMinuteGap"] != null && !"".Equals(mConfiguration["AILatestMinuteGap"]) && TransForm.IsInt(mConfiguration["AILatestMinuteGap"]))
//            if (aILatestMinuteGap != null && !"".Equals(aILatestMinuteGap) && TransForm.IsInt(aILatestMinuteGap))
//            {
//                //AILatestMinuteGap = int.Parse(mConfiguration["AILatestMinuteGap"]);
//                AILatestMinuteGap = int.Parse(aILatestMinuteGap);
//            }
//            //AI地数图像识别，节目错误开始时间和当前时间间隔，暂定阈值2分钟，小于则认为无效（不告警）
//            //if (mConfiguration["AIErrStartMinuteGap"] != null && !"".Equals(mConfiguration["AIErrStartMinuteGap"]))
//            if (aIErrStartMinuteGap != null && !"".Equals(aIErrStartMinuteGap))
//            {
//                //AIErrStartMinuteGap = Array.ConvertAll(mConfiguration["AIErrStartMinuteGap"].Split(','), int.Parse);
//                AIErrStartMinuteGap = Array.ConvertAll(aIErrStartMinuteGap.Split(','), int.Parse);
//            }

//            //数据库初始化
//            InitDb();

//            //alarmHisTableName = "alarm_data_his";
//            alarmHisPrefix = "alarm_his_";
//            alarmHisTableColumn = "ts,alarm_key,isintime,alarm,clear,get_time,upd_time,parentalarm_key,alarm_code,alarm_name,alarm_title,alarm_desc,alarm_level,alarm_value,alarm_id,alarm_type,station_id,station_name,station_level,subcenter_id,position_id,frequency,sub_system_id,device_type_id,program_name,program_summary,program_level,device_type,alarm_duration,schemaName,parno,parno_alias,alarm_locate";

//            try
//            {
//                InitCacheInfo();
//            }
//            catch { }

//            //确保主题存在
//            //string topic = mConfiguration["Kafka:Producer:Topic"];
//            string topic = paramInfo.GetValueOrDefault("Kafka.Producer.TopicSql", "svr_exec_sql"); ;
//#if DEBUG
//            topic = topic + "_ysw";
//#endif
//            string server = paramInfo.GetValueOrDefault("Kafka.Server", "");
//            string replicationFactor = paramInfo.GetValueOrDefault("Kafka.replicationFactor", "2");
//            //确保主题存在
//            //if (TransForm.IsInt(mConfiguration["Kafka:replicationFactor"]) && TransForm.IsInt(mConfiguration["Kafka:numPartitions"]))
//            if (TransForm.IsInt(replicationFactor))
//            {
//                CheckTopic(topic);
//            }

//            //kafka生产者池初始化
//            mProducerPool = new ProducerPool
//            {
//                Name = "ProducerPool",
//                producerFactory = new Kafka()
//                {
//                    producerOptions = new KafkaProducerOptions
//                    {
//                        //BootstrapServers = new string[] { mConfiguration["Kafka:Server"] },
//                        BootstrapServers = new string[] { server },
//                        InitializeCount = 3,
//                        //Key = "kafka",
//                        Topic = topic,  //需手工新增
//                        BatchSize = 16384,
//                        LingerMs = 5
//                    }
//                }.GetProducerFactor(),
//                Min = 10,  //最小poolNum个连接
//                //Max = maxPoolNum * 2,   //最大maxPoolNum个连接
//                Max = 0,   //最大个数。默认100，0表示无上限
//                IdleTime = 10,  //空闲时间20秒，超过该空闲时间的连接将被销毁释放，直到留下最后Min个
//                AllIdleTime = 60   //完全空闲时间120秒，把最后Min个连接都干掉
//            };


//            mLogger.LogInformation("初始化完成");
//        }

//        /// <summary>
//        /// 判断并创建主题
//        /// </summary>
//        /// <param name="topic"></param>
//        private void CheckTopic(string topic)
//        {
//            ////服务
//            //string server = mConfiguration["Kafka:Server"];
//            ////副本数
//            //string replicationFactor = mConfiguration["Kafka:replicationFactor"];
//            ////分区数
//            //string numPartitions = mConfiguration["Kafka:numPartitions"];

//            string server = paramInfo.GetValueOrDefault("Kafka.Server", "");
//            string replicationFactor = paramInfo.GetValueOrDefault("Kafka.replicationFactor", "2");
//            string numPartitions = paramInfo.GetValueOrDefault("Kafka.numPartitions", "5");

//            if (!Kafka.CheckAndCreateTopic(server, topic, short.Parse(replicationFactor), int.Parse(numPartitions)))
//            {
//                mLogger.LogError("主题【" + topic + "】不存在或创建失败！");
//            }
//        }

//        /// <summary>
//        /// 数据库连接初始化
//        /// </summary>
//        private void InitDb()
//        {
//            try
//            {
//                //0-pgsql,1-dm
//                string dbType = mConfiguration["DBType"];
//                if ("0".Equals(dbType))
//                {
//                    //添加解密
//                    dbConnection = new NpgsqlConnection(RsaEncrypt.DecryptFree(mConfiguration["PgSQLConnString"]));
//                    dbConnection.Open();
//                    IsDbConn = true;
//                    mLogger.LogInformation("pgSQL数据库连接成功！");
//                }
//                else
//                {
//                    //添加解密
//                    dbConnection = new DmConnection(RsaEncrypt.DecryptFree(mConfiguration["DMConnString"]));
//                    dbConnection.Open();
//                    IsDbConn = true;
//                    mLogger.LogInformation("达梦数据库连接成功！");
//                }
//            }
//            catch (Exception e)
//            {
//                IsDbConn = false;
//                mLogger.LogError("数据库连接失败！" + e.Message);
//            }
//        }

//        /// <summary>
//        /// 尝试重连数据库
//        /// </summary>
//        private void CheckDbState()
//        {
//            try
//            {
//                DbUtil.ExecReader(dbConnection, "select 1 col1", false);
//                if (dbConnection.State != ConnectionState.Open)
//                {
//                    dbConnection.Close();
//                    dbConnection.Open();
//                    mLogger.LogInformation("数据库连接成功！");
//                }
//                IsDbConn = true;
//            }
//            catch (Exception e)
//            {
//                IsDbConn = false;
//                mLogger.LogError("pgSQL数据库连接失败！" + e.Message);
//            }
//        }

//        /// <summary>
//        /// 初始化信息
//        /// </summary>
//        private void TimerInit()
//        {
//            Thread.Sleep(60 * 1000);
//            while (true)
//            {
//                try
//                {
//                    InitCacheInfo();
//                }
//                catch { }
//                Thread.Sleep(60 * 1000);
//            }
//        }

//        /// <summary>
//        /// 从redis更新缓存数据
//        /// </summary>
//        private void InitCacheInfo()
//        {
//            paramInfo = redisInit.HashGetAllDict<string>("paramInfo");
//            string tmpLoopAlarmFlags = paramInfo.GetValueOrDefault("loopAlarmFlag", "3");
//            if (TransForm.IsInt(tmpLoopAlarmFlags))
//            {
//                loopAlarmFlags = TransForm.Reverse(TransForm.intToBit(int.Parse(tmpLoopAlarmFlags))).ToCharArray();
//            }

//            string loopAlarmTimes = paramInfo.GetValueOrDefault("loopAlarmTimes", "13:00:00-17:05:00");
//            if (loopAlarmTimes != null && loopAlarmTimes.Contains("-"))
//            {
//                loopAlarmTime.beginTime = loopAlarmTimes.Split('-')[0];
//                loopAlarmTime.endTime = loopAlarmTimes.Split('-')[1];
//            }

//            Dictionary<string, Dictionary<string, string>> tmpStationsInfo = redisInit.StringGet<Dictionary<string, Dictionary<string, string>>>("stations");
//            stationsInfo = (tmpStationsInfo != null && tmpStationsInfo.Count > 0) ? tmpStationsInfo : stationsInfo;

//            Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>> tmpBroadcastTimeSet = redisInit.HashGetAllDict<Dictionary<string, List<Dictionary<string, string>>>>("broadcastTimeSet");
//            broadcastTimeSet = (tmpBroadcastTimeSet != null) ? tmpBroadcastTimeSet : broadcastTimeSet;

//            Dictionary<string, Dictionary<string, Dictionary<string, string>>> tmpStationFrqAndProgram = redisInit.StringGet<Dictionary<string, Dictionary<string, Dictionary<string, string>>>>("stationFrqAndProgram");
//            stationFrqAndProgram = (tmpStationFrqAndProgram != null && tmpStationFrqAndProgram.Count > 0) ? tmpStationFrqAndProgram : stationFrqAndProgram;

//            Dictionary<string, Dictionary<string, string>> tmpProgramInfo = redisInit.StringGet<Dictionary<string, Dictionary<string, string>>>("programInfo");
//            programInfo = (tmpProgramInfo != null && tmpProgramInfo.Count > 0) ? tmpProgramInfo : programInfo;

//            Dictionary<string, string> tmpSid2ProgramInfo = redisInit.StringGet<Dictionary<string, string>>("sid2ProgramInfo");
//            sid2ProgramInfo = (tmpSid2ProgramInfo != null && tmpSid2ProgramInfo.Count > 0) ? tmpSid2ProgramInfo : sid2ProgramInfo;

//            if (realAlarmInfo.Count > 0)
//            {
//                foreach (string staId in realAlarmInfo.Keys)
//                {
//                    Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> tmpModel = redisInit.HashGet<Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>>("stationAlarmNodeModel", staId);
//                    if (!JsonConvert.SerializeObject(realAlarmInfo[staId]).Equals(JsonConvert.SerializeObject(tmpModel)))
//                    {
//                        lock (realAlarmInfo)
//                        {
//                            realAlarmInfo[staId] = tmpModel ?? new();
//                        }
//                    }
//                }
//            }
//            if (alarmDataModel.Count > 0)
//            {
//                foreach (string mid in alarmDataModel.Keys)
//                {
//                    lock (alarmDataModel)
//                    {
//                        alarmDataModel[mid] = redisInit.HashGet<Dictionary<string, Dictionary<string, string>>>("stationAlarmDataModel", mid);
//                    }
//                }
//            }

//            Dictionary<string, AlarmRules> tmpAlarmRuleInfos = redisInit.StringGet<Dictionary<string, AlarmRules>>("alarmRuleInfos");
//            alarmRuleInfos = (tmpAlarmRuleInfos != null && tmpAlarmRuleInfos.Count > 0) ? tmpAlarmRuleInfos : alarmRuleInfos;

//            List<Dictionary<string, object>> tmpRelationAlarmInfos = redisInit.StringGet<List<Dictionary<string, object>>>("relationAlarmInfos");
//            relationAlarmInfos = (tmpRelationAlarmInfos != null && tmpRelationAlarmInfos.Count > 0) ? tmpRelationAlarmInfos : relationAlarmInfos;

//            Dictionary<string, Dictionary<string, Dictionary<string, string>>> tmpTimeAdvanceAndDelayInfo = redisInit.HashGetAllDict<Dictionary<string, Dictionary<string, string>>>("timeAdvanceAndDelayInfo");
//            timeAdvanceAndDelayInfo = (tmpTimeAdvanceAndDelayInfo != null && tmpTimeAdvanceAndDelayInfo.Count > 0) ? tmpTimeAdvanceAndDelayInfo : timeAdvanceAndDelayInfo;

//            Dictionary<string, Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>> tmpTimesTables = redisInit.StringGet<Dictionary<string, Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>>>("stationTimesTables");
//            timesTables = (tmpTimesTables != null && tmpTimesTables.Count > 0) ? tmpTimesTables : timesTables;

//            //特殊告警模板信息
//            Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>> tmpModelManagement = redisInit.StringGet<Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>>>("modelManagement");
//            modelManagement = (tmpModelManagement != null && tmpModelManagement.Count > 0) ? tmpModelManagement : modelManagement;

//            Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> tmpAlarmSets = redisInit.StringGet<Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>>("alarmSets");
//            alarmSets = (tmpAlarmSets != null) ? tmpAlarmSets : alarmSets;

//        }
//        #endregion

//        /// <summary>
//        /// 从real_alarm读取实时告警缓存信息
//        /// </summary>
//        /// <param name="stationId"></param>
//        private Dictionary<string, RealAlarmModel> GetRealAlarmInfoFromDb(string stationId)
//        {
//            Dictionary<string, RealAlarmModel> stationAlarm = new Dictionary<string, RealAlarmModel>();
//            try
//            {
//                if (IsDbConn)
//                {
//                    //pgsql里面的bool对应达梦的bit，为了同时兼容pgqsl和达梦，用case方法判断
//                    string sql = "select id,is_open,alarm_code,alarm_key,parent_alarm_key,alarm_id,alarm_type,alarm_name,alarm_title,alarm_desc,alarm_level,get_time,upd_time," +
//                        "case isend when '1' then 'true' when '0' then 'false' else isend||'' end isend,case isintime when '1' then 'true' when '0' then 'false' else isintime||'' end isintime," +
//                        "case alarm when '1' then 'true' when '0' then 'false' else alarm||'' end alarm,alarm_info,station_id,case clear when '1' then 'true' when '0' then 'false' else clear||'' end clear," +
//                        "subsys_id,devtype_id,case is_relation when '1' then 'true' when '0' then 'false' else is_relation||'' end is_relation " +
//                        " from real_alarm a where isend = false and alarm_key is not null and alarm_key != '' and station_id = '" + stationId + "'";

//                    List<Dictionary<string, string>> alarmDicts = new List<Dictionary<string, string>>();
//                    lock (dbConnection)
//                    {
//                        alarmDicts = DbUtil.ExecReader(dbConnection, sql);
//                    }
//                    if (alarmDicts != null && alarmDicts.Count > 0)
//                    {
//                        foreach (Dictionary<string, string> alarm in alarmDicts)
//                        {
//                            RealAlarmModel realAlarmModel = new()
//                            {
//                                alarmKey = alarm["alarm_key"],
//                                parentAlarmKey = alarm["parent_alarm_key"],
//                                alarmCode = alarm["alarm_code"],
//                                alarmId = int.Parse(alarm["alarm_id"]),
//                                alarmType = alarm["alarm_type"],
//                                alarmName = alarm["alarm_name"],
//                                alarmTitle = alarm["alarm_title"],
//                                alarmDesc = alarm["alarm_desc"],
//                                alarmLevel = alarm["alarm_level"],
//                                GetTime = TransForm.strTodateTime(alarm["get_time"]),
//                                clear = "T".Equals(alarm["clear"].ToUpper()) ? true : false,
//                                isRelation = "T".Equals(alarm["is_relation"].ToUpper()) ? true : false,
//                                isOpen = int.Parse(alarm["is_open"]),
//                                isInTime = "T".Equals(alarm["isintime"].ToUpper()) ? true : false,
//                                alarm = "T".Equals(alarm["alarm"].ToUpper()) ? true : false,
//                                alarmReal = true,
//                                subSysId = alarm["subsys_id"],
//                                devTypeId = alarm["devtype_id"]
//                            };
//                            realAlarmModel.alarmPre = realAlarmModel.alarm;

//                            string alarmInfo = alarm["alarm_info"];
//                            if (alarmInfo != null && !"".Equals(alarmInfo))
//                            {
//                                realAlarmModel.alarmInfo = JsonConvert.DeserializeObject<Dictionary<string, string>>(alarmInfo);
//                            }

//                            stationAlarm.TryAdd(realAlarmModel.alarmCode, realAlarmModel);
//                        }
//                    }
//                }
//            }
//            catch (Exception e)
//            {
//                mLogger.LogInformation("从数据库初始化告警异常，" + e.Message);
//            }

//            return stationAlarm;
//        }

//        #region 日志信息
//        /// <summary>
//        /// 定时打印提示信息
//        /// 定时重新初始化
//        /// </summary>
//        private void TimerTask()
//        {
//            Thread.Sleep(10 * 1000);
//            long num = 0;
//            long tmNum = 0;
//            int tagPre = DateTime.Now.Hour;
//            while (true)
//            {
//                //10秒处理一次
//                if (num % 10 == 0)
//                {
//                    mLogger.LogInformation(nodeName + " 节点数=" + nodeNum + " 当前节点号=" + (nodeNo + 1) +
//                        " 台站总数=" + stationsInfo.Count + " 当前节点处理数=" + taskNum.Sum() + "[" + string.Join(",", taskNum) + "]" +
//                        " 单次轮询用时=" + loopOnceTime.ToString() +
//                        (tmNum > 0 ? " 提交超时=" + tmNum : ""));

//                    lock (syncLock)
//                    {
//                        tmNum = timeOutNum;
//                        timeOutNum = 0;
//                        loopOnceTime = 0;
//                    }
//                }

//                if (DateTime.Now.Hour != tagPre)
//                {
//                    tagPre = DateTime.Now.Hour;
//                    lock (updateAlarmCodes)
//                    {
//                        updateAlarmCodes.Clear();
//                    }
//                }

//                if (num % 30 == 0)
//                {
//                    try
//                    {
//                        CheckDbState();
//                    }
//                    catch { }

//                    try
//                    {
//                        string hmstr = TransForm.DateTimeFormat(DateTime.Now, "HHmm");

//                        //统计一天内每分钟的告警缓存数量
//                        Dictionary<string, int> stationAlarmStat = redisInit.HashGetAllDict<int>("station_alarm_stat_cache");
//                        int sum = stationAlarmStat == null ? 0 : stationAlarmStat.Values.ToList().Sum();
//                        redisInit.HashSetAsync("station_alarm_stat_day_cache", hmstr, sum);

//                        stationAlarmStat = redisInit.HashGetAllDict<int>("station_alarm_stat_real");
//                        sum = stationAlarmStat == null ? 0 : stationAlarmStat.Values.ToList().Sum();
//                        redisInit.HashSetAsync("station_alarm_stat_day_real", hmstr, sum);
//                    }
//                    catch { }
//                }

//                if (num > 10 * 10000)
//                {
//                    num = 0;
//                }
//                num++;
//                Thread.Sleep(1000);
//            }
//        }
//        #endregion

//        #region Kafka
//        /// <summary>
//        /// 处理数据
//        /// </summary>
//        /// <param name="o"></param>
//        private void PublishDatas(object o)
//        {
//            IClientProducer producer = mProducerPool.Get(); //借出
//            Dictionary<string, string> message = (Dictionary<string, string>)o;
//            try
//            {
//                producer.Publish(
//                    new KafkaMessage() { Message = o, Key = message["key"] },
//                    result =>
//                    {
//                        if (result == null)
//                        {
//                            lock (syncLock)
//                            {
//                                timeOutNum++;
//                            }
//                        }
//                        else
//                        {

//                        }
//                    });//发送到kafka中
//            }
//            catch (Exception ex)
//            {
//                mLogger.LogError("数据推送错误，" + ex);

//                if (ex.Message.Contains("Unknown topic") && producer != null)
//                {
//                    CheckTopic(((DefaultClientProducer)producer).topic);
//                }
//            }
//            finally
//            {
//                mProducerPool.Put(producer);    //归还
//            }
//        }
//        #endregion

//        #region 告警轮询
//        /// <summary>
//        /// 定时更新告警信息
//        /// </summary>
//        /// <param name="threadNo">任务编号</param>
//        private void TimerAlarm(int threadNo)
//        {
//            Thread.Sleep(1000);
//            RedisHelper redisAlarm = new RedisHelper(redisConnString, mLogger);
//            IBatch batch = redisAlarm.CreateBatch();
//            //记录所有台站的工位号
//            Dictionary<string, Dictionary<string, string>> stationPositionIds = new();
//            while (true)
//            {
//                try
//                {
//                    var sw = Stopwatch.StartNew();
//                    //实时告警处理
//                    SetRealAlarms(threadNo, redisAlarm, batch, stationPositionIds);
//                    //统计单次轮询时间，用于打印日志到前台，便于观察
//                    if (loopOnceTime < sw.ElapsedMilliseconds)
//                    {
//                        lock (syncLock)
//                        {
//                            loopOnceTime = sw.ElapsedMilliseconds;
//                        }
//                    }
//#if DEBUG
//                    mLogger.LogInformation("轮询用时=" + sw.ElapsedMilliseconds);
//#endif
//                }
//                catch { }
//                finally
//                {
//                    //Thread.Sleep(1 * 1000);
//                    //加快频率，确保告警的准确性
//                    Thread.Sleep(200);
//                }
//            }
//        }

//        #region 告警辅助方法
//        /// <summary>
//        /// 判断台站是否离线
//        /// </summary>
//        /// <param name="checkKey"></param>
//        /// <returns></returns>
//        private bool GetStationOffLine(string stationId, RedisHelper redis)
//        {
//            //是否离线
//            string val = redis.StringGet("online_" + stationId);
//            if (val != null && "0".Equals(val))
//            {
//                return false;
//            }
//            return true;
//        }

//        /// <summary>
//        /// 判断台站是否断连，即是否ping不通
//        /// </summary>
//        /// <param name="checkKey"></param>
//        /// <returns></returns>
//        private bool GetStationConnect(string stationId, RedisHelper redis)
//        {
//            try
//            {
//                //是否连接
//                string val = redis.StringGet("connect_" + stationId);
//                if (val != null && "0".Equals(val))
//                {
//                    return false;
//                }
//                return true;
//            }
//            catch
//            {
//                return false;
//            }
//        }

//        /// <summary>
//        /// 获取工位号在线状态
//        /// </summary>
//        /// <param name="positionId"></param>
//        /// <returns></returns>
//        private string GetPositionOffLine(string positionId, RedisHelper redis)
//        {
//            //是否离线
//            string val = redis.StringGet("online_" + positionId);
//            //获取不到值也判断为离线
//            if (val == null || "".Equals(val))
//            {
//                val = "1";
//            }
//            return val;
//        }

//        /// <summary>
//        /// 判断当前时间是否在时间表内
//        /// </summary>
//        /// <param name="weekTimesTable"></param>
//        /// <param name="addMinutes">调频、中波开机时间提前告警分钟数25，其它0</param>
//        /// <param name="subMinutes">调频、中波开机时间延迟告警分钟数5，其它0，此参数暂时无用，默认都是0</param>
//        /// <returns></returns>
//        private bool CheckInTime(Dictionary<string, List<Dictionary<string, string>>> weekTimesTable, int addMinutes = 0, int subMinutes = 0)
//        {
//            bool inTime = true;

//            try
//            {
//                DateTime dtNow = DateTime.Now;

//                //获取星期几，然后从星期数组中获取数据判断
//                string weekNo = ((int)dtNow.DayOfWeek).ToString();
//                if (weekTimesTable.ContainsKey(weekNo))
//                {
//                    List<Dictionary<string, string>> wTimesTables = weekTimesTable[weekNo];
//                    foreach (var timesTable in wTimesTables)
//                    {
//                        string timeStart = timesTable["show_start_time"];
//                        string timeEnd = timesTable["show_end_time"];

//                        //判断开始结束时间
//                        if ("".Equals(timeStart) || "".Equals(timeEnd) || timeStart.Equals(timeEnd))
//                        {
//                            continue;
//                        }

//                        //调频和中波，开始时间提前addMinutes（默认25）分钟告警
//                        //这里将dtbgn提前，再用当前时间比对
//                        DateTime dtbgn = DateTime.Parse(timeStart);
//                        DateTime dtend = DateTime.Parse(timeEnd);

//                        //时间点矛盾的剔除
//                        if (dtend < dtbgn)
//                        {
//                            continue;
//                        }

//                        //if (dtNow >= dtbgn.AddMinutes(-1 * addMinutes) && dtNow <= dtend)
//                        if (dtNow >= dtbgn.AddMinutes(-1 * addMinutes) && dtNow <= dtend.AddMinutes(subMinutes))
//                        {
//                            inTime = true;
//                            break;
//                        }
//                        else
//                        {
//                            inTime = false;
//                        }
//                    }
//                }
//            }
//            catch
//            {
//                inTime = true;
//            }

//            return inTime;
//        }
//        #endregion

//        #region 模型获取
//        /// <summary>
//        /// 获取衍生告警模型
//        /// </summary>
//        /// <param name="redisCache"></param>
//        /// <returns></returns>
//        private Dictionary<int, DerivedRealAlarm> GetDerivedAlarm(string redisCache)
//        {
//            Dictionary<int, DerivedRealAlarm> derivedRealAlarms;
//            try
//            {
//                if (redisCache != null && !"".Equals(redisCache))
//                {
//                    derivedRealAlarms = JsonConvert.DeserializeObject<Dictionary<int, DerivedRealAlarm>>(redisCache);

//                    //移除多余的告警
//                    Dictionary<int, string> dictDerivedId = relationAlarmInfos.ToDictionary(d => int.Parse(d["derived_alarm_id"].ToString()), d => "");
//                    List<int> lsDerivedId = derivedRealAlarms.Keys.ToList();
//                    foreach (int derivedId in lsDerivedId)
//                    {
//                        if (!dictDerivedId.ContainsKey(derivedId))
//                        {
//                            derivedRealAlarms.Remove(derivedId);
//                        }
//                    }
//                    foreach (var relationAlarmInfo in relationAlarmInfos)
//                    {
//                        string derivedId = relationAlarmInfo["derived_alarm_id"].ToString();
//                        DerivedRealAlarm derivedRealAlarm = derivedRealAlarms.ContainsKey(int.Parse(derivedId)) ? derivedRealAlarms[int.Parse(derivedId)] : new DerivedRealAlarm();
//                        if (derivedRealAlarms.ContainsKey(int.Parse(derivedId)))
//                        {
//                            derivedRealAlarms[int.Parse(derivedId)] = GetDerivedRealAlarm(relationAlarmInfo, derivedRealAlarm);
//                        }
//                        else
//                        {
//                            //derivedRealAlarms.TryAdd(int.Parse(derivedId), derivedRealAlarm);
//                            derivedRealAlarms.TryAdd(int.Parse(derivedId), GetDerivedRealAlarm(relationAlarmInfo, derivedRealAlarm));
//                        }
//                    }
//                    if (derivedRealAlarms.Count != relationAlarmInfos.Count)
//                    {
//                        derivedRealAlarms = GetBasicDerivedAlarm();
//                    }
//                }
//                else
//                {
//                    derivedRealAlarms = GetBasicDerivedAlarm();
//                }
//            }
//            catch
//            {
//                derivedRealAlarms = GetBasicDerivedAlarm();
//            }

//            return derivedRealAlarms;
//        }

//        /// <summary>
//        /// 获取衍生告警基本初始化模型
//        /// </summary>
//        /// <returns></returns>
//        private Dictionary<int, DerivedRealAlarm> GetBasicDerivedAlarm()
//        {
//            //key：衍生告警ID
//            Dictionary<int, DerivedRealAlarm> derivedRealAlarms = new Dictionary<int, DerivedRealAlarm>();
//            foreach (var relationAlarmInfo in relationAlarmInfos)
//            {
//                DerivedRealAlarm derivedRealAlarm = GetDerivedRealAlarm(relationAlarmInfo, new DerivedRealAlarm());
//                derivedRealAlarms.TryAdd(derivedRealAlarm.derivedId, derivedRealAlarm);
//            }

//            return derivedRealAlarms;
//        }

//        /// <summary>
//        /// 根据relationAlarmInfo更新derivedRealAlarm
//        /// </summary>
//        /// <param name="relationAlarmInfo"></param>
//        /// <param name="derivedRealAlarm"></param>
//        /// <returns></returns>
//        private DerivedRealAlarm GetDerivedRealAlarm(Dictionary<string, Object> relationAlarmInfo, DerivedRealAlarm derivedRealAlarm)
//        {
//            string derivedId = relationAlarmInfo["derived_alarm_id"].ToString();
//            derivedRealAlarm.derivedId = int.Parse(derivedId);
//            derivedRealAlarm.rulerName = relationAlarmInfo.ContainsKey("ruler_name") ? relationAlarmInfo["ruler_name"].ToString() : derivedRealAlarm.rulerName;
//            derivedRealAlarm.subSystemId = relationAlarmInfo.ContainsKey("sub_system_id") ? int.Parse(relationAlarmInfo["sub_system_id"].ToString()) : derivedRealAlarm.subSystemId;
//            derivedRealAlarm.relationMethod = relationAlarmInfo.ContainsKey("relation_method") ? relationAlarmInfo["relation_method"].ToString() : "";
//            derivedRealAlarm.activeTimeout = relationAlarmInfo.ContainsKey("activetimeout") ? int.Parse(relationAlarmInfo["activetimeout"].ToString()) : derivedRealAlarm.activeTimeout;
//            derivedRealAlarm.rulerDescribe = relationAlarmInfo.ContainsKey("ruler_describe") ? relationAlarmInfo["ruler_describe"].ToString() : "";
//            derivedRealAlarm.derivedAlarmTitle = relationAlarmInfo.ContainsKey("derived_alarm_title") ? relationAlarmInfo["derived_alarm_title"].ToString() : "";
//            derivedRealAlarm.derivedAlarmLevel = relationAlarmInfo.ContainsKey("derived_alarm_level") ? int.Parse(relationAlarmInfo["derived_alarm_level"].ToString()) : derivedRealAlarm.derivedAlarmLevel;
//            derivedRealAlarm.alarmLevel = relationAlarmInfo.ContainsKey("alarm_level") ? int.Parse(relationAlarmInfo["alarm_level"].ToString()) : derivedRealAlarm.alarmLevel;
//            derivedRealAlarm.clearMode = relationAlarmInfo.ContainsKey("clear_mode") ? int.Parse(relationAlarmInfo["clear_mode"].ToString()) : derivedRealAlarm.clearMode;
//            derivedRealAlarm.used = relationAlarmInfo.ContainsKey("is_used") ? "1".Equals(relationAlarmInfo["is_used"].ToString()) : derivedRealAlarm.used;
//            derivedRealAlarm.alarmTitle = relationAlarmInfo.ContainsKey("alarm_title") ? relationAlarmInfo["alarm_title"].ToString() : derivedRealAlarm.alarmTitle;
//            derivedRealAlarm.alarmTitleId = relationAlarmInfo.ContainsKey("alarm_title_id") ? relationAlarmInfo["alarm_title_id"].ToString() : derivedRealAlarm.alarmTitleId;
//            derivedRealAlarm.alarmId = relationAlarmInfo.ContainsKey("alarm_id") ? int.Parse(relationAlarmInfo["alarm_id"].ToString()) : derivedRealAlarm.alarmId;
//            derivedRealAlarm.subSysId = relationAlarmInfo.ContainsKey("sub_system_id") ? relationAlarmInfo["sub_system_id"].ToString() : derivedRealAlarm.subSysId;
//            derivedRealAlarm.alarmType = relationAlarmInfo.ContainsKey("alarm_type") ? relationAlarmInfo["alarm_type"].ToString() : "";
//            derivedRealAlarm.devTypeId = relationAlarmInfo.ContainsKey("device_type_id") ? relationAlarmInfo["device_type_id"].ToString() : "";
//            derivedRealAlarm.devTypeName = relationAlarmInfo.ContainsKey("device_type_name") ? relationAlarmInfo["device_type_name"].ToString() : "";
//            derivedRealAlarm.sub_system = relationAlarmInfo.ContainsKey("sub_system") ? relationAlarmInfo["sub_system"].ToString() : "";

//            List<Dictionary<string, string>> sourceAlarms = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(relationAlarmInfo["rConditionArray"].ToString());
//            Dictionary<int, int> tmpSids = new();
//            foreach (var sourceAlarm in sourceAlarms)
//            {
//                int sourceAlarmId = sourceAlarm.ContainsKey("source_alarm_condition_id") ? int.Parse(sourceAlarm["source_alarm_condition_id"].ToString()) : 1;
//                tmpSids.TryAdd(sourceAlarmId, 0);
//                SourceAlarmCondition SourceAlarmCondition = derivedRealAlarm.SourceAlarmConditions.ContainsKey(sourceAlarmId) ? derivedRealAlarm.SourceAlarmConditions[sourceAlarmId] : new();
//                SourceAlarmCondition.SourceAlarmId = sourceAlarmId;
//                SourceAlarmCondition.deviceTypeId = sourceAlarm.ContainsKey("device_type_id") ? int.Parse(sourceAlarm["device_type_id"].ToString()) : SourceAlarmCondition.deviceTypeId;
//                SourceAlarmCondition.VenderId = sourceAlarm.ContainsKey("vender_id") ? int.Parse(sourceAlarm["vender_id"].ToString()) : SourceAlarmCondition.VenderId;

//                string alarmIds = sourceAlarm["alarm_id_array"];
//                string rAlarmIds = (sourceAlarm.ContainsKey("collect_alarm_id") && sourceAlarm["collect_alarm_id"] != null && !"".Equals(sourceAlarm["collect_alarm_id"])) ? sourceAlarm["collect_alarm_id"] : alarmIds;
//                //写法有修改，新增了短横杆区间写法
//                //SourceAlarmCondition.AlarmIds = Array.ConvertAll(alarmIds.Split(','), int.Parse).ToList();
//                //采用下面这种写法
//                //调整为判断ID
//                Dictionary<int, int> dictIds = new();
//                foreach (string alarmId in alarmIds.Split(','))
//                {
//                    if (!alarmId.Contains('-'))
//                    {
//                        if (!dictIds.ContainsKey(int.Parse(alarmId)))
//                        {
//                            dictIds.TryAdd(int.Parse(alarmId), 0);
//                        }
//                    }
//                    else
//                    {
//                        string[] alarmIdArr = alarmId.Split('-');
//                        if (alarmIdArr.Length == 2 && int.Parse(alarmIdArr[0]) < int.Parse(alarmIdArr[1]))
//                        {
//                            for (int s = int.Parse(alarmIdArr[0]); s <= int.Parse(alarmIdArr[1]); s++)
//                            {
//                                if (!dictIds.ContainsKey(s))
//                                {
//                                    dictIds.TryAdd(s, 0);
//                                }
//                            }
//                        }
//                    }
//                }
//                SourceAlarmCondition.AlarmIds = dictIds.Keys.ToList();

//                //关联ID
//                Dictionary<int, int> rDictIds = new();
//                foreach (string alarmId in rAlarmIds.Split(','))
//                {
//                    if (!alarmId.Contains('-'))
//                    {
//                        if (!rDictIds.ContainsKey(int.Parse(alarmId)))
//                        {
//                            rDictIds.TryAdd(int.Parse(alarmId), 0);
//                        }
//                    }
//                    else
//                    {
//                        string[] alarmIdArr = alarmId.Split('-');
//                        if (alarmIdArr.Length == 2 && int.Parse(alarmIdArr[0]) < int.Parse(alarmIdArr[1]))
//                        {
//                            for (int s = int.Parse(alarmIdArr[0]); s <= int.Parse(alarmIdArr[1]); s++)
//                            {
//                                if (!rDictIds.ContainsKey(s))
//                                {
//                                    rDictIds.TryAdd(s, 0);
//                                }
//                            }
//                        }
//                    }
//                }
//                SourceAlarmCondition.RelateAlarmIds = rDictIds.Keys.ToList();

//                if (derivedRealAlarm.SourceAlarmConditions.ContainsKey(sourceAlarmId))
//                {
//                    derivedRealAlarm.SourceAlarmConditions[sourceAlarmId] = SourceAlarmCondition;
//                }
//                else
//                {
//                    derivedRealAlarm.SourceAlarmConditions.TryAdd(SourceAlarmCondition.SourceAlarmId, SourceAlarmCondition);
//                }
//            }
//            List<int> sids = derivedRealAlarm.SourceAlarmConditions.Keys.ToList();
//            foreach (int sid in sids)
//            {
//                if (!tmpSids.ContainsKey(sid))
//                {
//                    derivedRealAlarm.SourceAlarmConditions.Remove(sid);
//                }
//            }
//            return derivedRealAlarm;
//        }

//        /// <summary>
//        /// 获取台站实时告警
//        /// </summary>
//        /// <param name="stationId"></param>
//        /// <returns></returns>
//        private Dictionary<string, RealAlarmModel> GetStationAlarm(string stationId, RedisHelper redis)
//        {
//            Dictionary<string, RealAlarmModel> stationAlarm;
//            //从redis获取该台站的实时告警
//            string val = redis.StringGet("realAlarm_" + stationId);
//            //val = "";
//            if (val == null || "".Equals(val))
//            {
//                //当redis缓存被清理时
//                //添加尝试从数据库读取
//                stationAlarm = GetRealAlarmInfoFromDb(stationId);
//            }
//            else
//            {
//                try
//                {
//                    stationAlarm = JsonConvert.DeserializeObject<Dictionary<string, RealAlarmModel>>(val);
//                }
//                catch
//                {
//                    //stationAlarm = new Dictionary<string, RealAlarmModel>();

//                    //发生错误时，改从数据库读取
//                    stationAlarm = GetRealAlarmInfoFromDb(stationId);
//                }
//            }

//            //if (stationAlarm != null)
//            //{
//            //    foreach (string key in stationAlarm.Keys)
//            //    {
//            //        stationAlarm[key].alarmTimeout = alarmTime;
//            //        stationAlarm[key].alarmEndTimeout = alarmEndTime;
//            //    }
//            //}

//            return stationAlarm;
//        }

//        /// <summary>
//        /// 获取工单信息
//        /// </summary>
//        /// <param name="redis"></param>
//        /// <returns></returns>
//        private Dictionary<string, string> GetSheetInfo(RedisHelper redis)
//        {
//            Dictionary<string, string> sheetInfo;
//            try
//            {
//                sheetInfo = redis.HashGetAllDict<string>("alarmSheetInfo");
//            }
//            catch
//            {
//                sheetInfo = null;
//            }
//            return sheetInfo ?? new();
//        }

//        /// <summary>
//        /// 获取台站关联、衍生告警告警模型
//        /// </summary>
//        /// <param name="stationId"></param>
//        /// <returns></returns>
//        private Dictionary<int, DerivedRealAlarm> GetDerivedRealAlarms(string stationId, RedisHelper redis)
//        {
//            //关联、衍生告警告警模型
//            string val = redis.StringGet("derivedAlarm_" + stationId);
//            Dictionary<int, DerivedRealAlarm> derivedRealAlarms = GetDerivedAlarm(val);

//            //if (derivedRealAlarms != null)
//            //{
//            //    foreach (int key in derivedRealAlarms.Keys)
//            //    {
//            //        derivedRealAlarms[key].activeTimeout = alarmTime;
//            //        derivedRealAlarms[key].connTimeout = alarmEndTime;
//            //    }
//            //}
//            return derivedRealAlarms.OrderBy(p => p.Key).ToDictionary(p => p.Key, o => o.Value);
//        }

//        /// <summary>
//        /// 获取台站告警清除信息
//        /// </summary>
//        /// <param name="stationId"></param>
//        /// <returns></returns>
//        private Dictionary<string, bool> GetRealAlarmRm(string stationId, RedisHelper redis)
//        {
//            //告警清除
//            //string val = redis.StringGet("realAlarmRm_" + stationId);
//            //Dictionary<string, bool> realAlarmRm = null;
//            //if (val != null && !"".Equals(val))
//            //{
//            //    realAlarmRm = JsonConvert.DeserializeObject<Dictionary<string, bool>>(val);
//            //}

//            //获取告警移除信息
//            Dictionary<string, bool> realAlarmRm = redisInit.HashGetAllDict<bool>("realAlarmRm");
//            if (realAlarmRm != null && realAlarmRm.Count > 0)
//            {
//                realAlarmRm = realAlarmRm.Where(d => !d.Value).ToDictionary(d => d.Key, d => d.Value);
//            }

//            return realAlarmRm;
//        }

//        /// <summary>
//        /// 获取特定台站告警模型
//        /// </summary>
//        /// <param name="stationId"></param>
//        private void GetStationRealAlarmInfoModel(string stationId, RedisHelper redis)
//        {
//            if (!realAlarmInfo.ContainsKey(stationId))
//            {
//                Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> tmpModel = redis.HashGet<Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>>("stationAlarmNodeModel", stationId);
//                if (tmpModel != null)
//                {
//                    realAlarmInfo.TryAdd(stationId, tmpModel);
//                }
//            }
//        }

//        private Dictionary<string, Dictionary<string, string>> GetModelParaInfo(string mid, RedisHelper redis)
//        {
//            if (!alarmDataModel.ContainsKey(mid))
//            {
//                lock (alarmDataModel)
//                {
//                    alarmDataModel.TryAdd(mid, redis.HashGet<Dictionary<string, Dictionary<string, string>>>("stationAlarmDataModel", mid));
//                }
//            }
//            return alarmDataModel.ContainsKey(mid) ? alarmDataModel[mid] : null;
//        }
//        #endregion

//        #region 实时告警处理
//        /// <summary>
//        /// 实时告警处理
//        /// </summary>
//        /// <param name="threadNo">任务分解数量</param>
//        private void SetRealAlarms(int threadNo, RedisHelper redis, IBatch batch, Dictionary<string, Dictionary<string, string>> stationPositionIds)
//        {
//            try
//            {
//                int taskNumTmp = 0;
//                int orderAllNo = 0;
//                int orderNo = 0;
//                foreach (string stationId in stationsInfo.Keys)
//                {
//#if DEBUG
//                    if (!stationId.Contains("0101"))
//                    {
//                        continue;
//                    }
//#endif
//                    //台站是整形 求余nodeNum为nodeNo
//                    //相当于根据副本数，平均分配任务
//                    //if (TransForm.IsInt(stationId) && long.Parse(stationId) % nodeNum == nodeNo)
//                    if (nodeNum > 0 && orderAllNo % nodeNum == nodeNo)
//                    {
//                        if (!dealStation.ContainsKey(stationId))
//                        {
//                            lock (dealStation)
//                            {
//                                dealStation.TryAdd(stationId, false);
//                            }
//                        }

//                        //台站继续拆分多个线程号来执行
//                        //orderNo根据当前节点分配的编号来分配
//                        if (orderNo % threadNum == threadNo)
//                        {
//                            //计算实时当前副本分配到的任务数
//                            taskNumTmp++;

//                            if (!stationPositionIds.ContainsKey(stationId))
//                            {
//                                stationPositionIds.TryAdd(stationId, new Dictionary<string, string>());
//                            }
//                            RealAlarmsTask(stationId, stationsInfo[stationId], redis, batch, stationPositionIds);
//                        }
//                        orderNo++;
//                    }
//                    orderAllNo++;
//                }

//                lock (taskNum)
//                {
//                    taskNum[threadNo] = taskNumTmp;
//                }
//            }
//            catch (Exception e)
//            {
//                mLogger.LogError("实时告警更新异常，" + e);
//            }
//        }

//        /// <summary>
//        /// 批量获取数据
//        /// </summary>
//        /// <param name="redis"></param>
//        /// <param name="stationPositionId"></param>
//        /// <returns></returns>
//        private Dictionary<string, Dictionary<string, string>> GetNodeDatas(RedisHelper redis, IBatch batch, Dictionary<string, string> stationPositionId)
//        {
//            Dictionary<string, Dictionary<string, string>> nodeDatas = new Dictionary<string, Dictionary<string, string>>();
//            try
//            {
//                Dictionary<string, Task<HashEntry[]>> taskList = new();
//                foreach (string positionId in stationPositionId.Keys)
//                {
//                    taskList.TryAdd(positionId, batch.HashGetAllAsync("DATA_" + positionId));
//                }
//                batch.Execute();

//                foreach (string positionId in taskList.Keys)
//                {
//                    nodeDatas.TryAdd(positionId, taskList[positionId].Result.ToDictionary(key => key.Name.ToString(), value => redis.ConvertObj<string>(value.Value)));
//                }
//            }
//            catch { }
//            return nodeDatas;
//        }

//        /// <summary>
//        /// 台站实时告警更新
//        /// </summary>
//        /// <param name="stationId"></param>
//        /// <param name="stationInfo"></param>
//        private void RealAlarmsTask(string stationId, Dictionary<string, string> stationInfo, RedisHelper redis, IBatch batch, Dictionary<string, Dictionary<string, string>> stationPositionIds)
//        {
//            //这里只是实时正在告警的数据
//            Dictionary<string, RealAlarmModel> stationAlarm = GetStationAlarm(stationId, redis);
//            //轮询前的哈希值，判断告警是否有变化
//            string hashPre = string.Join(",", stationAlarm.Where(d => !d.Value.isEnd).ToDictionary(d => d.Key, d => d.Value.alarmInfo.ContainsKey("alarm_hash") ? d.Value.alarmInfo["alarm_hash"] : "").Values.ToList());

//            //关联、衍生告警告警模型
//            Dictionary<int, DerivedRealAlarm> derivedRealAlarms = GetDerivedRealAlarms(stationId, redis);
//            //告警清除信息
//            Dictionary<string, bool> realAlarmRm = GetRealAlarmRm(stationId, redis);
//            //记录告警清除条目数
//            //int rmCount = realAlarmRm == null ? 0 : realAlarmRm.Count;

//            //告警工单信息
//            Dictionary<string, string> sheetInfo = GetSheetInfo(redis);

//            //配置了模型的，进行告警明细判断
//            GetStationRealAlarmInfoModel(stationId, redis);
//            //台站级别
//            string stationLevel = stationInfo["station_level"];

//            //动态（参数录入）停播标识，分台站、频率
//            //Dictionary<string, bool> onceAlarms = broadcastTimeSet.ContainsKey(stationId)? broadcastTimeSet[stationId].ToDictionary(d => d.Key, d => d.Value.Where(l => TransForm.strTodateTime(l["begin_time"]) <= DateTime.Now && TransForm.strTodateTime(l["end_time"]) >= DateTime.Now).ToList().Count > 0) : new();
//            //新增了提前开机时间参数，这里判断时直接加上，即end_time直接减去提前开机时间
//            Dictionary<string, bool> onceAlarms = broadcastTimeSet.ContainsKey(stationId) ? broadcastTimeSet[stationId].ToDictionary(d => d.Key,
//                            d => d.Value.Where(l => TransForm.strTodateTime(l["begin_time"]) <= DateTime.Now &&
//                            TransForm.strTodateTime(l["end_time"]).AddMinutes(
//                                -1 * ((l.ContainsKey("advance_time") && !"".Equals(l["advance_time"]) && TransForm.IsInt(l["advance_time"])) ? int.Parse(l["advance_time"]) : 0)
//                                ) >= DateTime.Now).ToList().Count > 0) : new();

//            //新结构判断方法
//            if (realAlarmInfo.ContainsKey(stationId))
//            {
//                //台站下一级是工位号
//                Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> stationRealAlarm = realAlarmInfo[stationId];
//                //该台站时间表数据
//                Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>> stationTimesTable = timesTables.ContainsKey(stationId) ? timesTables[stationId] : new Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>();
//                //频率节目信息匹配
//                Dictionary<string, Dictionary<string, string>> frqToProgram = stationFrqAndProgram.ContainsKey(stationId) ? stationFrqAndProgram[stationId] : new();

//                /**************新判断方法**********************/
//                StationAlarmMatchInfo stationAlarmMatchInfo = new();
//                //数据改为存hash，一次性把该工位号下的所有数据都读取回来
//                //Dictionary<string, Dictionary<string, string>> nodeDatas = new();
//                Dictionary<string, Dictionary<string, string>> nodeDatas = GetNodeDatas(redis, batch, stationPositionIds[stationId]);
//                //所有存在的设备
//                Dictionary<string, int> allDevices = new();

//                //stationDevIsEnables
//                //先循环获取台站设备is_enable字段信息，因为后面从缓存读取设备数据时都要用到
//                Dictionary<string, int> isEnables = new();
//                foreach (string positionId in stationRealAlarm.Keys)
//                {
//                    if ("".Equals(positionId))
//                    {
//                        continue;
//                    }

//                    //工位号下一级才是设备
//                    Dictionary<string, Dictionary<string, Dictionary<string, string>>> realAlarmDev = stationRealAlarm[positionId];
//                    foreach (string device in realAlarmDev.Keys)
//                    {
//                        if (realAlarmDev[device].ContainsKey("rConfig"))
//                        {
//                            Dictionary<string, string> deviceInfo = realAlarmDev[device]["rConfig"];

//                            //Dictionary<string, Dictionary<string, string>> modelParaInfos1 = GetModelParaInfo(deviceInfo["static_model_id"].ToString(), redis);
//                            //if (modelParaInfos != null && modelParaInfos.Count > 0)
//                            //{ 
//                            //    //is_enable处理
//                            //    //0-无设备 1-有设备 2-无此参数
//                            //    int isEnable = 2;
//                            //    //是否有is_enable字段
//                            //    bool hasEnable = modelParaInfos.ContainsKey("is_enable");
//                            //    //1~3级台站不用此参数
//                            //    if (hasEnable && TransForm.IsInt(modelParaInfos["is_enable"]["para_value"]) &&
//                            //        !("1".Equals(stationLevel) || "2".Equals(stationLevel) || "3".Equals(stationLevel)))
//                            //    {
//                            //        isEnable = int.Parse(modelParaInfos["is_enable"]["para_value"]);
//                            //    }
//                            //    isEnables.TryAdd(device, isEnable);
//                            //}

//                            //dynamic_model_id is_enable数据改成工动态表读取
//                            Dictionary<string, Dictionary<string, string>> modelParaInfos = GetModelParaInfo(deviceInfo["dynamic_model_id"].ToString(), redis);
//                            if (modelParaInfos != null && modelParaInfos.Count > 0)
//                            {
//                                //is_enable处理
//                                //0-无设备 1-有设备 2-无此参数
//                                int isEnable = 2;
//                                //是否有is_enable字段
//                                bool hasEnable = modelParaInfos.ContainsKey("is_enable");
//                                //1~3级台站不用此参数
//                                if (hasEnable && !("1".Equals(stationLevel) || "2".Equals(stationLevel) || "3".Equals(stationLevel)))
//                                {
//                                    string tmpParno = modelParaInfos["is_enable"]["parno"].ToUpper();
//                                    string tmpVal = GetValFromSource(positionId, tmpParno, nodeDatas, redis);
//                                    isEnable = TransForm.IsInt(tmpVal) ? int.Parse(tmpVal) : isEnable;
//                                }

//                                isEnables.TryAdd(device, isEnable);
//                            }
//                        }
//                    }
//                }
//                //写入全局变量
//                if (!stationDevIsEnables.ContainsKey(stationId))
//                {
//                    stationDevIsEnables.TryAdd(stationId, isEnables);
//                }
//                else
//                {
//                    stationDevIsEnables[stationId] = isEnables;
//                }

//                //先循环获取台站频率、天线、时间表、节目等信息
//                foreach (string positionId in stationRealAlarm.Keys)
//                {
//                    if ("".Equals(positionId))
//                    {
//                        continue;
//                    }

//                    //工位号下一级才是设备
//                    Dictionary<string, Dictionary<string, Dictionary<string, string>>> realAlarmDev = stationRealAlarm[positionId];
//                    foreach (string device in realAlarmDev.Keys)
//                    {
//                        if (realAlarmDev[device].ContainsKey("rConfig"))
//                        {
//                            Dictionary<string, string> deviceInfo = realAlarmDev[device]["rConfig"];
//                            Dictionary<string, Dictionary<string, string>> modelParaInfos = null;
//                            if (deviceInfo.ContainsKey("static_model_id") && !"".Equals(deviceInfo["static_model_id"]))
//                            {
//                                modelParaInfos = GetModelParaInfo(deviceInfo["static_model_id"].ToString(), redis);
//                            }
//                            if (deviceInfo.ContainsKey("dynamic_model_id") && !"".Equals(deviceInfo["dynamic_model_id"]))
//                            {
//                                Dictionary<string, Dictionary<string, string>> tmpParaInfo = GetModelParaInfo(deviceInfo["dynamic_model_id"].ToString(), redis);
//                                //modelParaInfos = (modelParaInfos == null ? tmpParaInfo : (tmpParaInfo == null ? modelParaInfos : modelParaInfos.Concat(tmpParaInfo).ToDictionary(k => k.Key, k => k.Value)));
//                                //20240407 可能静态表和动态表重复的，这里想办法剔除
//                                modelParaInfos = (modelParaInfos == null ? tmpParaInfo : (tmpParaInfo == null ? modelParaInfos : modelParaInfos.Concat(tmpParaInfo.Where(d => !modelParaInfos.ContainsKey(d.Key))).ToDictionary(k => k.Key, k => k.Value)));

//                                //CheckDeviceEnable判断设备是否存在，目前只针对0x0702下调频发射机
//                                if (modelParaInfos != null && modelParaInfos.Count > 0 && CheckDeviceEnable(device, nodeDatas, deviceInfo, modelParaInfos, redis))
//                                {
//                                    //最终一级才是字段model，告警模型关联信息
//                                    //先去判断频率、天线、时间表、节目，得出应该告警的positionId-device
//                                    stationAlarmMatchInfo = GetStationAlarmModelMatchInfo(stationId, positionId, device, deviceInfo, stationTimesTable, frqToProgram, nodeDatas, stationAlarmMatchInfo, modelParaInfos, redis);
//                                    if (!allDevices.ContainsKey(device))
//                                    {
//                                        allDevices.TryAdd(device, 0);
//                                    }
//                                }
//                            }
//                        }
//                    }
//                }

//                //写入一条工位号和频率的对应关系到redis，下发加速功能时会用到，后面其他地方也可能用到
//                //redis.HashSet("positionIdToFrq", stationId, stationAlarmMatchInfo.positionIdToFrq);
//                redis.HashSetAsync("positionIdToFrq", stationId, stationAlarmMatchInfo.positionIdToFrq);
//                //redis.HashSetAsync("stationAlarmMatchInfo", stationId, stationAlarmMatchInfo);

//                //是否在时间表内参数，写入缓存，其它地方用到（如AI地数图像识别）
//                //redis.HashSetAsync("frqIntime", stationId, stationAlarmMatchInfo.frqIntime.Where(d => !d.Key.Contains("_")).ToDictionary(d => d.Key, d => d.Value));

//                //后根据频率、天线、时间表、节目等信息，循环生成告警
//                foreach (string positionId in stationRealAlarm.Keys)
//                {
//                    if (positionId == null || "".Equals(positionId))
//                    {
//                        continue;
//                    }

//                    //工位号下一级才是告警
//                    Dictionary<string, Dictionary<string, Dictionary<string, string>>> realAlarmDev = stationRealAlarm[positionId];
//                    DateTime newTime = GetPositionLatestTime(positionId, nodeDatas, redis);

//                    //工位号下一级是带末端节点的key
//                    foreach (string device in realAlarmDev.Keys)
//                    {
//                        //allDevices存在的设备才告警
//                        if (realAlarmDev[device].ContainsKey("rConfig") && allDevices.ContainsKey(device))
//                        {
//                            Dictionary<string, string> deviceInfo = realAlarmDev[device]["rConfig"];
//                            Dictionary<string, Dictionary<string, string>> modelParaInfos = null;
//                            if (deviceInfo.ContainsKey("static_model_id") && !"".Equals(deviceInfo["static_model_id"]))
//                            {
//                                modelParaInfos = GetModelParaInfo(deviceInfo["static_model_id"].ToString(), redis);
//                            }

//                            //动态字段判断告警
//                            if (deviceInfo.ContainsKey("dynamic_model_id") && !"".Equals(deviceInfo["dynamic_model_id"]))
//                            {
//                                Dictionary<string, Dictionary<string, string>> dynamicModelParaInfo = GetModelParaInfo(deviceInfo["dynamic_model_id"].ToString(), redis);
//                                //modelParaInfos = (modelParaInfos == null ? dynamicModelParaInfo : (dynamicModelParaInfo == null ? modelParaInfos : modelParaInfos.Concat(dynamicModelParaInfo).ToDictionary(k => k.Key, k => k.Value)));
//                                //20240407 可能静态表和动态表重复的，这里想办法剔除
//                                modelParaInfos = (modelParaInfos == null ? dynamicModelParaInfo : (dynamicModelParaInfo == null ? modelParaInfos : modelParaInfos.Concat(dynamicModelParaInfo.Where(d => !modelParaInfos.ContainsKey(d.Key))).ToDictionary(k => k.Key, k => k.Value)));
//                                if (dynamicModelParaInfo != null && dynamicModelParaInfo.Count > 0)
//                                {
//                                    //告警明细
//                                    RealAlarmModels(stationId, stationInfo, positionId, newTime, device, dynamicModelParaInfo.Keys.ToList(),
//                                        modelParaInfos, deviceInfo, stationAlarm, realAlarmRm, nodeDatas, frqToProgram, stationAlarmMatchInfo,
//                                        sheetInfo, onceAlarms, redis);
//                                }
//                            }
//                        }
//                    }
//                }
//                /**************新判断方法**********************/

//                //不是衍生告警，且工位号不在stationRealAlarm的
//                //20221107 ysw 新增判断key是否包含在allDevices，因为配置的设备节点也可能会修改
//                List<string> uselessCodes = stationAlarm.Keys.Where(k =>
//                {
//                    //bool matchDev = allDevices.Keys.Where(device => k.Contains(device.ToUpper())).ToList().Count == 0;
//                    bool matchDev = allDevices.Keys.Where(device => k.StartsWith(device.ToUpper())).ToList().Count == 0;
//                    return !k.StartsWith(stationId + "-DERIVEDALARM-") && matchDev;
//                }).ToList();
//                //清除残留告警
//                ClearUselessAlarm(uselessCodes, stationAlarm);

//                //记录所有工位号
//                stationPositionIds[stationId] = nodeDatas.ToDictionary(d => d.Key, d => "");
//            }

//            //循环完毕，判断每个衍生告警是否告警，判断台站断连告警
//            //根据告警id，设置衍生告警
//            DerivedAlarm(stationId, stationInfo, stationAlarm, derivedRealAlarms, realAlarmRm, sheetInfo, onceAlarms, redis);

//            //轮询后的哈希值，判断告警是否有变化
//            string hash = string.Join(",", stationAlarm.Where(d => !d.Value.isEnd).ToDictionary(d => d.Key, d => d.Value.alarmInfo["alarm_hash"]).Values.ToList());

//            //判断告警是否有变化
//            //有变化马上发送
//            string channel = "alarmChange_" + stationId;
//            if (!hash.Equals(hashPre))
//            {
//                //发布变化
//                //redis.StringSet(channel, hash, TimeSpan.FromSeconds(15));
//                redis.StringSetAsync(channel, hash, TimeSpan.FromSeconds(15));
//                //redis.Publish(channel, "1");
//                redis.PublishAsync(channel, "1");
//            }
//            //没有变化时，N秒内发送多次，避免因为redis订阅机制问题，接口无法接收到订阅
//            else if (redis.KeyExists(channel))
//            {
//                //redis.Publish(channel, "1");
//                redis.PublishAsync(channel, "1");
//            }

//            //写入前判断告警清除
//            //if (realAlarmRm != null && rmCount != realAlarmRm.Count)
//            //{
//            //    redis.StringSet("realAlarmRm_" + stationId, realAlarmRm);
//            //}

//            //实时告警写入
//            //redis.StringSet("realAlarm_" + stationId, stationAlarm);
//            redis.StringSetAsync("realAlarm_" + stationId, stationAlarm);
//            //记录台站告警缓存数量
//            redis.HashSetAsync("station_alarm_stat_cache", stationId, stationAlarm.Count);
//            redis.HashSetAsync("station_alarm_stat_real", stationId, stationAlarm.Where(d => !d.Value.isEnd).ToList().Count);
//            //衍生告警写入
//            //redis.StringSet("derivedAlarm_" + stationId, derivedRealAlarms);
//            redis.StringSetAsync("derivedAlarm_" + stationId, derivedRealAlarms);
//        }

//        /// <summary>
//        /// 清除残留告警
//        /// </summary>
//        /// <param name="uselessCodes"></param>
//        /// <param name="stationAlarm"></param>
//        private void ClearUselessAlarm(List<string> uselessCodes, Dictionary<string, RealAlarmModel> stationAlarm)
//        {
//            if (uselessCodes.Count > 0)
//            {
//                DateTime newTime = DateTime.Now;
//                //清除垃圾告警
//                foreach (string alarmCode in uselessCodes)
//                {
//                    //包含的未结束的，修改时间
//                    if (stationAlarm.ContainsKey(alarmCode))
//                    {
//                        if (!stationAlarm[alarmCode].isEnd)
//                        {
//                            stationAlarm[alarmCode].isEnd = true;
//                            stationAlarm[alarmCode].alarmInfo["isEnd"] = stationAlarm[alarmCode].isEnd.ToString();
//                            stationAlarm[alarmCode].UpdTime = newTime;
//                            stationAlarm[alarmCode].alarmInfo["end_time"] = TransForm.DateTimeFormat(stationAlarm[alarmCode].UpdTime);

//                            ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetRealAlarmSql(stationAlarm[alarmCode], 2) } });
//                            //开始或当前在播出时间内才保存历史
//                            if (stationAlarm[alarmCode].inTimeAlarm)
//                            {
//                                ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "0" }, { "key", alarmCode }, { "sql", GetSaveAlarmSql(stationAlarm[alarmCode]) } });
//                                ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetSaveAlarmSqlDM(stationAlarm[alarmCode]) } });
//                            }

//                            stationAlarm.Remove(alarmCode);
//                        }
//                        else
//                        {
//                            stationAlarm.Remove(alarmCode);
//                        }
//                    }
//                }
//            }
//        }

//        /// <summary>
//        /// 判断设备是否存在
//        /// 目前只针对0x0702下调频发射机0x8021
//        /// </summary>
//        /// <param name="device"></param>
//        /// <param name="nodeDatas"></param>
//        /// <param name="deviceInfo"></param>
//        /// <param name="modelParaInfo"></param>
//        /// <returns></returns>
//        private bool CheckDeviceEnable(string device,
//            Dictionary<string, Dictionary<string, string>> nodeDatas,
//            Dictionary<string, string> deviceInfo,
//            Dictionary<string, Dictionary<string, string>> modelParaInfo,
//            RedisHelper redis)
//        {
//            //是否有该设备
//            bool isDevEnable = true;

//            //1-3级台站调频电视1+1 300W 0x0702发射机0x8021才会有这种情况device_type_id=5
//            //pair_count参数 发射机组数量（实际1+1套数） 0x0702主控有该参数，且全部关联到0x0702下每一台发射机
//            //dev_no_status（DevNo）参数 发射机编号（1、2、3、4、5、6等），只有0x0702下发射机有该参数
//            //dev_exist_status（Dev1Exist）参数 是否有1号机（有备机）0无1有，0x0702下发射机有该参数
//            //if (device.Contains("_0X0702_") && deviceInfo.ContainsKey("device_type_id") && "5".Equals(deviceInfo["device_type_id"]))
//            if (device.Contains("_0X8021_") && deviceInfo.ContainsKey("device_type_id") && "5".Equals(deviceInfo["device_type_id"]))
//            {
//                List<string> lsPairCount = modelParaInfo.Keys.Where(k => k.ToUpper().Equals("PAIR_COUNT")).ToList();
//                List<string> lsDevNo = modelParaInfo.Keys.Where(k => k.ToUpper().Equals("DEV_NO_STATUS")).ToList();
//                List<string> lsDev1Exist = modelParaInfo.Keys.Where(k => k.ToUpper().Equals("DEV_EXIST_STATUS")).ToList();
//                //有这三个参数
//                if (lsPairCount.Count > 0 && lsDevNo.Count > 0 && lsDev1Exist.Count > 0)
//                {
//                    isDevEnable = false;
//                    string pairCount = lsPairCount[0];
//                    string devNo = lsDevNo[0];
//                    string dev1Exist = lsDev1Exist[0];
//                    string valPairCount = GetFromPositionModelDatas(nodeDatas, deviceInfo, pairCount, modelParaInfo, redis);
//                    string valDevNo = GetFromPositionModelDatas(nodeDatas, deviceInfo, devNo, modelParaInfo, redis);
//                    string valDev1Exist = GetFromPositionModelDatas(nodeDatas, deviceInfo, dev1Exist, modelParaInfo, redis);

//                    //工位编号
//                    string pno = device.Split('_')[device.Split('_').Length - 1];

//                    //关联工位号编号获取
//                    string rPid = deviceInfo.ContainsKey("relation_position_id") ? deviceInfo["relation_position_id"] : "";
//                    //父级工位编号，因为发射机的编号pno会从1编号到12，所以rpno为2时要加6
//                    string rpno = "".Equals(rPid) ? "1" : (rPid.Split('_')[rPid.Split('_').Length - 1]);

//                    if (TransForm.IsInt(valPairCount) && TransForm.IsInt(valDevNo) && TransForm.IsInt(rpno)
//                        && TransForm.IsInt(pno) && int.Parse(pno) <= (int.Parse(valPairCount) * 2 + (int.Parse(rpno) - 1) * 6)
//                        && TransForm.IsInt(valDev1Exist))
//                    {
//                        int iPairCount = int.Parse(valPairCount);
//                        int iDevNo = int.Parse(valDevNo);
//                        int iDev1Exist = int.Parse(valDev1Exist);
//                        //套数大于0，且发射机编号在套数*2内
//                        //主机一定有，备机根据iDev1Exist判断
//                        if (iPairCount > 0 && iDevNo <= iPairCount * 2)
//                        {
//                            for (int no = 1; no <= iPairCount; no++)
//                            {
//                                if (iDevNo == (no * 2 - 1))
//                                {
//                                    isDevEnable = true;
//                                    break;
//                                }
//                                else if (iDevNo == no * 2 && iDev1Exist == 1)
//                                {
//                                    isDevEnable = true;
//                                    break;
//                                }
//                            }
//                        }
//                    }
//                }
//            }

//            return isDevEnable;
//        }

//        /// <summary>
//        /// 新模型用
//        /// 先去判断频率、天线、时间表、节目，得出应该告警的positionId-device
//        /// </summary>
//        /// <param name="positionId"></param>
//        /// <param name="device"></param>
//        /// <param name="realAlarm"></param>
//        /// <param name="stationTimesTable"></param>
//        /// <param name="frqToProgram"></param>
//        /// <param name="nodeDatas"></param>
//        /// <param name="stationAlarmMatchInfo"></param>
//        /// <returns></returns>
//        private StationAlarmMatchInfo GetStationAlarmModelMatchInfo(string stationId,
//            string positionId, string device,
//            Dictionary<string, string> deviceInfo,
//            Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>> stationTimesTable,
//            Dictionary<string, Dictionary<string, string>> frqToProgram,
//            Dictionary<string, Dictionary<string, string>> nodeDatas,
//            StationAlarmMatchInfo stationAlarmMatchInfo,
//            Dictionary<string, Dictionary<string, string>> modelParaInfo,
//            RedisHelper redis)
//        {
//            string rPositionId = deviceInfo.ContainsKey("relation_position_id") ? deviceInfo["relation_position_id"] : "";

//            //目前来看，只针对1~3级台站数字电视，因为数字电视1+1切换器有时候无法提供天线信息，需要根据入射功率取判断，以便于做一个纠正，避免误告警
//            if (device.Contains("_0X0303_"))
//            {
//                //获取功率信息
//                int ipower = GetTxIpowerModel(nodeDatas, deviceInfo, modelParaInfo, redis);
//                if (ipower > 0)
//                {
//                    //记录设备功率信息
//                    stationAlarmMatchInfo.positionToIpower.TryAdd(device, ipower);
//                }
//            }

//            //找出频率字段 根据频率字段，匹配频率值 key：频率或者前缀 value：频率
//            Dictionary<string, Dictionary<string, string>> frqDict = GetFrqDictModel(nodeDatas, deviceInfo, modelParaInfo, redis);
//            //频率天线在位情况
//            Dictionary<string, bool> txOnline = GetTxOnlineModel(positionId, nodeDatas, deviceInfo, modelParaInfo, redis);

//            if (frqDict.Count > 0)
//            {
//                //位置包含前缀信息
//                stationAlarmMatchInfo.positionToFrqPrefix.TryAdd(device, new());
//            }

//            //调频和中波 告警时间为时间表开机时间再提前25分钟（默认），有特殊的后续添加
//            //子系统ID，用于筛选出调频和中波
//            //sub_system_id=1为信号源系统
//            //sub_system_id=2为调频系统
//            //sub_system_id=3为电视系统
//            //sub_system_id=4为中波系统
//            //sub_system_id=6为辅助系统 暂无数据
//            //sub_system_id=8为收测系统
//            string subSysId = deviceInfo.ContainsKey("sub_system_id") ? deviceInfo["sub_system_id"] : "";
//            //调频、中波告警默认提前分钟数
//            int addMinutes = 0;
//            //if ("2".Equals(subSysId) || "4".Equals(subSysId))
//            //{
//            //    addMinutes = defaltAddMinutes;
//            //}

//            foreach (string prefix in frqDict.Keys)
//            {
//                //频率
//                string frq = frqDict[prefix]["frq"];
//                string subSysIdFrq = subSysId + "_" + frqDict[prefix]["frq"];
//                string pid = frqDict[prefix]["pid"];

//                //addMinutes 调频、中波告警默认提前分钟数 如果后续新增频率特殊处理，在这里新增逻辑，修改addMinutes
//                //20231130先从内存（定时从redis缓存拿）查找，没有就在数据中找，还没有就取默认值defaltAddMinutes
//                //timeAdvanceAndDelayInfo
//                if ("2".Equals(subSysId) || "4".Equals(subSysId))
//                {
//                    string realPid = !"".Equals(rPositionId) ? rPositionId : positionId;
//                    //在数据中找
//                    string advanceKey = "";
//                    string delayKey = "";
//                    //调频300W的字符串
//                    if (positionId.ToUpper().Contains("_0X0702_") || rPositionId.ToUpper().Contains("_0X0702_")
//                        || positionId.ToUpper().Contains("_0X8021_") || rPositionId.ToUpper().Contains("_0X8021_"))
//                    {
//                        advanceKey = frq + "_STARTUPTIMEADVANCE_0_DEVPAIRCONFIG";
//                        delayKey = frq + "_SHUTDOWNTIMEDELAY_0_DEVPAIRCONFIG";
//                    }
//                    //调频1000W和中波一样
//                    else
//                    {
//                        advanceKey = frq + "_STARTUPTIMEADVANCE_0_GLOBALCONFIG";
//                        delayKey = frq + "_SHUTDOWNTIMEDELAY_0_GLOBALCONFIG";
//                    }
//                    string timeAdvance = GetFromPositionModelDatas(nodeDatas, deviceInfo, advanceKey, modelParaInfo, redis);
//                    //延时时间暂时不用
//                    string timeDelay = GetFromPositionModelDatas(nodeDatas, deviceInfo, delayKey, modelParaInfo, redis);

//                    //判断缓存是否有
//                    if (timeAdvanceAndDelayInfo != null && timeAdvanceAndDelayInfo.ContainsKey(stationId) && timeAdvanceAndDelayInfo[stationId] != null
//                        && timeAdvanceAndDelayInfo[stationId].ContainsKey(frq) && timeAdvanceAndDelayInfo[stationId][frq] != null
//                        && timeAdvanceAndDelayInfo[stationId][frq].ContainsKey("time_advance") && TransForm.IsInt(timeAdvanceAndDelayInfo[stationId][frq]["time_advance"]))
//                    {
//                        addMinutes = int.Parse(timeAdvanceAndDelayInfo[stationId][frq]["time_advance"]);
//                        int subMinutes = int.Parse(timeAdvanceAndDelayInfo[stationId][frq]["time_delay"]);

//                        //有变化时更新到数据库
//                        if ((timeAdvance != null && !"".Equals(timeAdvance) && TransForm.IsInt(timeAdvance) && int.Parse(timeAdvance) > 0 && addMinutes != int.Parse(timeAdvance))
//                            || (timeDelay != null && !"".Equals(timeDelay) && TransForm.IsInt(timeDelay) && int.Parse(timeDelay) > 0 && subMinutes != int.Parse(timeDelay)))
//                        {
//                            //有变化时更新到数据库
//                            string sql = "update time_advance_delay set time_advance={0}, time_delay={1} " +
//                                " where station_id='{2}' and sub_system_id='{3}' and position_id='{4}' and frequency='{5}'";
//                            sql = string.Format(sql, timeAdvance, timeDelay, stationId, subSysId, realPid, frq);
//                            ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", realPid + "_" + frq }, { "sql", sql } });
//                        }
//                    }
//                    else
//                    {
//                        //从数据找到的，是否符合条件
//                        if (timeAdvance != null && !"".Equals(timeAdvance) && TransForm.IsInt(timeAdvance) && int.Parse(timeAdvance) > 0)
//                        {
//                            addMinutes = int.Parse(timeAdvance);
//                            if (timeDelay != null && !"".Equals(timeDelay) && TransForm.IsInt(timeDelay))
//                            {
//                                //符合条件了，提交sql到Kafka，写入数据库
//                                string sql = "insert into time_advance_delay(station_id,sub_system_id,position_id,frequency,time_advance,time_delay) " +
//                                    " select '{0}','{1}','{2}','{3}',{4},{5} " +
//                                    " where not exists(select 1 from time_advance_delay where station_id='{6}' and sub_system_id='{7}' and position_id='{8}' and frequency='{9}') ";
//                                sql = string.Format(sql, stationId, subSysId, realPid, frq, timeAdvance, timeDelay, stationId, subSysId, realPid, frq);
//                                ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", realPid + "_" + frq }, { "sql", sql } });
//                            }
//                        }
//                        else
//                        {
//                            //都没找到，取默认值
//                            addMinutes = defaltAddMinutes;
//                        }
//                    }
//                }

//                //CheckInTime() 根据时间表，判断是否在播出时间内
//                //true-在 false-不在 默认true
//                //stationAlarmMatchInfo.frqIntime.TryAdd(frq, stationTimesTable.ContainsKey(frq) ? CheckInTime(stationTimesTable[frq], addMinutes) : true);
//                //不直接赋值，采用或
//                bool isInTime = (stationTimesTable.ContainsKey(frq) ? CheckInTime(stationTimesTable[frq], addMinutes) : true);
//                if (!stationAlarmMatchInfo.frqIntime.ContainsKey(frq))
//                {
//                    stationAlarmMatchInfo.frqIntime.TryAdd(frq, isInTime);
//                }
//                else
//                {
//                    stationAlarmMatchInfo.frqIntime[frq] = stationAlarmMatchInfo.frqIntime[frq] || isInTime;
//                }
//                //拼接上子系统编号，作为key也存储一份
//                if (!stationAlarmMatchInfo.frqIntime.ContainsKey(subSysIdFrq))
//                {
//                    stationAlarmMatchInfo.frqIntime.TryAdd(subSysIdFrq, isInTime);
//                }
//                else
//                {
//                    stationAlarmMatchInfo.frqIntime[subSysIdFrq] = stationAlarmMatchInfo.frqIntime[subSysIdFrq] || isInTime;
//                }

//                //得到节目信息
//                if (frqToProgram.ContainsKey(frq))
//                {
//                    stationAlarmMatchInfo.frqProgram.TryAdd(frq, frqToProgram[frq]);
//                }

//                //记录该频率所被哪些设备包含
//                if (!stationAlarmMatchInfo.frqToPosition.ContainsKey(frq))
//                {
//                    stationAlarmMatchInfo.frqToPosition.TryAdd(frq, new());
//                }
//                stationAlarmMatchInfo.frqToPosition[frq].TryAdd(device, positionId);
//                stationAlarmMatchInfo.positionToFrqPrefix[device].TryAdd(prefix, frq);

//                //工位号对应频率
//                if (!stationAlarmMatchInfo.positionIdToFrq.ContainsKey(pid))
//                {
//                    stationAlarmMatchInfo.positionIdToFrq.TryAdd(pid, new());
//                }
//                if (!stationAlarmMatchInfo.positionIdToFrq[pid].ContainsKey(frq))
//                {
//                    stationAlarmMatchInfo.positionIdToFrq[pid].TryAdd(frq, "");
//                }

//                //给关联工位号也加上频率
//                if (rPositionId != null && !"".Equals(rPositionId))
//                {
//                    if (!stationAlarmMatchInfo.positionIdToFrq.ContainsKey(rPositionId))
//                    {
//                        stationAlarmMatchInfo.positionIdToFrq.TryAdd(rPositionId, new());
//                    }
//                    if (!stationAlarmMatchInfo.positionIdToFrq[rPositionId].ContainsKey(frq))
//                    {
//                        stationAlarmMatchInfo.positionIdToFrq[rPositionId].TryAdd(frq, "");
//                    }
//                }
//            }

//            if (txOnline.Count > 0)
//            {
//                //位置天线信息
//                stationAlarmMatchInfo.positionToTxPrefix.TryAdd(device, new());
//            }
//            foreach (string prefix in txOnline.Keys)
//            {
//                //天线在位情况
//                bool location = txOnline[prefix];
//                stationAlarmMatchInfo.positionToTxPrefix[device].TryAdd(prefix, location);
//            }
//            return stationAlarmMatchInfo;
//        }

//        /// <summary>
//        /// 根据告警id，设置衍生告警
//        /// </summary>
//        /// <param name="stationId">台站ID</param>
//        /// <param name="stationAlarm">台站告警集合，包含历史告警</param>
//        /// <param name="derivedRealAlarms">台站衍生告警集</param>
//        /// <param name="realAlarmRm">前端告警移除操作记录的alarmCode集</param>
//        private void DerivedAlarm(string stationId, Dictionary<string, string> stationInfo,
//            Dictionary<string, RealAlarmModel> stationAlarm,
//            Dictionary<int, DerivedRealAlarm> derivedRealAlarms,
//            Dictionary<string, bool> realAlarmRm,
//            Dictionary<string, string> sheetInfo,
//            Dictionary<string, bool> onceAlarms,
//            RedisHelper redis)
//        {
//            //台站是否停播
//            bool onceStationAlarm = onceAlarms.ContainsKey("station") ? onceAlarms["station"] : false;

//            //台站是否ping不通
//            DateTime newTimeConnect = redis.StringGet<DateTime>("connect_time_" + stationId);
//            newTimeConnect = (newTimeConnect == default(DateTime)) ? DateTime.Now : newTimeConnect;
//            bool stationConnect = GetStationConnect(stationId, redis);

//            //台站是否离线判断
//            //修改定义为是否上报超时
//            DateTime newTimeOffLine = redis.StringGet<DateTime>("newest_time_" + stationId);
//            newTimeOffLine = (newTimeOffLine == default(DateTime)) ? DateTime.Now : newTimeOffLine;
//            bool stationOffLine = GetStationOffLine(stationId, redis);

//#if DEBUG
//            //测试环境默认全部在线，方便测试
//            //stationConnect = false;
//            //stationOffLine = false;
//#endif

//            //上报超时和ping不通同时发生时，产生台站断连
//            bool stationDisConnAlarm = true;

//            //台站断连，关联台站无法ping通和台站数据上报超时，这个时关联code
//            List<string> alarmCodes = new();
//            //记录所有alarmCode判断是否由垃圾alarmCode需要删除，避免因为修改表结构造成垃圾告警
//            Dictionary<string, string> alarmCodesAll = new();

//            //台站级别
//            string stationLevel = stationInfo["station_level"];

//            //循环完毕，判断每个衍生告警是否告警
//            //根据告警id，设置衍生告警
//            foreach (int derivedId in derivedRealAlarms.Keys)
//            {
//                DerivedRealAlarm derivedRealAlarm = derivedRealAlarms[derivedId];

//                //自定义一个alarmKey
//                //台站id + derivedAlarm + 衍生告警id
//                string alarmCode = stationId + "-DERIVEDALARM-" + derivedId.ToString();
//                alarmCodesAll.TryAdd(alarmCode, "");
//                string parentAlarmKey = "";
//                //当前告警
//                bool isAlarm = true;
//                //该条衍生告警，是否单独产生新的告警，目前的逻辑是，relationMethod=5的时候，是不产生告警的
//                bool createAlarm = true;

//                //是否告警清除，执行一次，直接将isAlarm置为false，修改clear为true即可
//                if (realAlarmRm != null && realAlarmRm.ContainsKey(alarmCode))
//                {
//                    if (stationAlarm.ContainsKey(alarmCode))
//                    {
//                        stationAlarm[alarmCode].clear = true;
//                        stationAlarm[alarmCode].alarmInfo["clear"] = true.ToString();
//                    }
//                    isAlarm = false;
//                    //realAlarmRm.Remove(alarmCode);
//                    //redis.HashSet("realAlarmRm", alarmCode, true);
//                    redis.HashSetAsync("realAlarmRm", alarmCode, true);
//                }
//                else if (stationAlarm.ContainsKey(alarmCode))
//                {
//                    stationAlarm[alarmCode].clear = false;
//                    stationAlarm[alarmCode].alarmInfo["clear"] = false.ToString();
//                }

//                //cover_mode 覆盖方式 当前有：调频-1 中波-2 地数-3 其它-4
//                //dictionary_info表 dictionary_english_name=cover_mode的
//                //默认其它

//                //是否台站级别告警
//                //除了123、124、125，都是非台站级别告警 20240904还有主控离线，修改判断方式subSystemId为0的都是true
//                //bool isStationAlarm = true;
//                bool isStationAlarm = (derivedRealAlarm.subSystemId == 0);
//                bool isInTime = true;

//                //启用才告警
//                if (derivedRealAlarm.used && isAlarm)
//                {
//                    //系统根据derived_alarm_id排序，小的肯定排前面
//                    //123 台站数据上报超时
//                    //124 台站无法ping通
//                    //125 台站断连
//                    //254 静音告警
//                    switch (derivedRealAlarm.alarmId)
//                    {
//                        //台站数据上报超时
//                        case 123:
//                            isAlarm = isAlarm ? derivedRealAlarm.CheckAlarm(stationOffLine, newTimeOffLine) : isAlarm;

//                            //通过与，获得是否数据上报和ping不通同时发生stationDisConnAlarm
//                            stationDisConnAlarm = (stationDisConnAlarm && isAlarm);
//                            alarmCodes.Add(alarmCode);
//                            break;
//                        //台站无法ping通
//                        case 124:
//                            isAlarm = isAlarm ? derivedRealAlarm.CheckAlarm(stationConnect, newTimeConnect) : isAlarm;

//                            //通过与，获得是否数据上报和ping不通同时发生stationDisConnAlarm
//                            stationDisConnAlarm = (stationDisConnAlarm && isAlarm);
//                            alarmCodes.Add(alarmCode);
//                            break;
//                        //台站断连
//                        case 125:
//                            isAlarm = isAlarm ? derivedRealAlarm.CheckAlarm(stationDisConnAlarm, DateTime.Now) : isAlarm;

//                            //获得台站断连的开始结束时间
//                            //开始时间为超时和ping不通大的那个时间
//                            //结束时间为超时和ping不通小的那个时间
//                            int ng = 0;
//                            int ne = 0;
//                            foreach (string alCode in alarmCodes)
//                            {
//                                if (isAlarm)
//                                {
//                                    derivedRealAlarm.AlarmTimeBgn = (ng == 0 ? stationAlarm[alCode].GetTime : (derivedRealAlarm.AlarmTimeBgn > stationAlarm[alCode].GetTime ? derivedRealAlarm.AlarmTimeBgn : stationAlarm[alCode].GetTime));
//                                    ng++;
//                                }
//                                if (stationAlarm.ContainsKey(alCode) && !isAlarm && stationAlarm[alCode].isEnd)
//                                {
//                                    derivedRealAlarm.AlarmTimeEnd = (ne == 0 ? stationAlarm[alCode].UpdTime : (derivedRealAlarm.AlarmTimeEnd > stationAlarm[alCode].UpdTime ? stationAlarm[alCode].UpdTime : derivedRealAlarm.AlarmTimeEnd));
//                                    ne++;
//                                }
//                            }
//                            break;
//                        default:
//                            //isStationAlarm = false;

//                            //其他告警，
//                            //254 静音告警
//                            //关联方式relationMethod 1:主次关联  2:阈值关联 3:频次关联，关联字典表
//                            //1:主次关联，子告警与
//                            //子告警都告警，才告警
//                            if ("1".Equals(derivedRealAlarm.relationMethod))
//                            {
//                                isInTime = false;
//                                DateTime getTime = DateTime.Now;
//                                DateTime endTime = DateTime.Now;
//                                //普通告警的parentAlarmKey设置
//                                int childCount = 0;
//                                int alarmIdsCount = 0;
//                                foreach (SourceAlarmCondition sourceAlarmCondition in derivedRealAlarm.SourceAlarmConditions.Values)
//                                {
//                                    foreach (int alarmId in sourceAlarmCondition.AlarmIds)
//                                    {
//                                        alarmIdsCount++;
//                                        foreach (RealAlarmModel realAlarm in stationAlarm.Values)
//                                        {
//                                            if (realAlarm.alarmId == alarmId)
//                                            {
//                                                childCount++;
//                                                bool tmpAlarm = (!realAlarm.isEnd && realAlarm.alarm);
//                                                //isAlarm = (isAlarm && !realAlarm.isEnd);
//                                                isAlarm = (isAlarm && tmpAlarm);
//                                                if (!realAlarm.isEnd)
//                                                {
//                                                    isInTime = (isInTime || realAlarm.alarm);
//                                                }
//                                                //if (!realAlarm.isEnd && getTime > realAlarm.GetTime)
//                                                if (tmpAlarm && getTime > realAlarm.GetTime)
//                                                {
//                                                    getTime = realAlarm.GetTime;
//                                                }
//                                                //if (realAlarm.isEnd && endTime > realAlarm.UpdTime)
//                                                if (!tmpAlarm && endTime > realAlarm.UpdTime)
//                                                {
//                                                    endTime = realAlarm.UpdTime;
//                                                }
//                                            }
//                                        }
//                                    }
//                                }

//                                //isAlarm = (isAlarm && childCount >= 0);
//                                isAlarm = (isAlarm && childCount >= alarmIdsCount);
//                                isAlarm = derivedRealAlarm.CheckAlarm(isAlarm, getTime);
//                                if (!isAlarm)
//                                {
//                                    derivedRealAlarm.AlarmTimeEnd = endTime;
//                                }
//                            }
//                            //2:阈值关联
//                            else if ("2".Equals(derivedRealAlarm.relationMethod))
//                            {
//                                isAlarm = false;
//                            }
//                            //3:频次关联，关联字典表
//                            else if ("3".Equals(derivedRealAlarm.relationMethod))
//                            {
//                                isAlarm = false;
//                            }
//                            //4:关联告警，子告警或
//                            //子告警只要有告警，就告警
//                            else if ("4".Equals(derivedRealAlarm.relationMethod))
//                            {
//                                isAlarm = false;
//                                isInTime = false;
//                                DateTime getTime = DateTime.Now;
//                                DateTime endTime = DateTime.Now;
//                                //普通告警的parentAlarmKey设置
//                                //int childCount = 0;
//                                //int alarmIdsCount = 0;
//                                foreach (SourceAlarmCondition sourceAlarmCondition in derivedRealAlarm.SourceAlarmConditions.Values)
//                                {
//                                    foreach (int alarmId in sourceAlarmCondition.AlarmIds)
//                                    {
//                                        //alarmIdsCount++;
//                                        foreach (RealAlarmModel realAlarm in stationAlarm.Values)
//                                        {
//                                            if (realAlarm.alarmId == alarmId)
//                                            {
//                                                //childCount++; 
//                                                //isAlarm = (isAlarm || !realAlarm.isEnd);
//                                                bool tmpAlarm = (!realAlarm.isEnd && realAlarm.alarm);
//                                                isAlarm = (isAlarm || tmpAlarm);
//                                                if (!realAlarm.isEnd)
//                                                {
//                                                    isInTime = (isInTime || realAlarm.alarm);
//                                                }
//                                                //if (!realAlarm.isEnd && getTime > realAlarm.GetTime)
//                                                if (tmpAlarm && getTime > realAlarm.GetTime)
//                                                {
//                                                    getTime = realAlarm.GetTime;
//                                                }
//                                                //if (realAlarm.isEnd && endTime > realAlarm.UpdTime)
//                                                if (!tmpAlarm && endTime > realAlarm.UpdTime)
//                                                {
//                                                    endTime = realAlarm.UpdTime;
//                                                }
//                                            }
//                                        }
//                                    }
//                                }

//                                isAlarm = derivedRealAlarm.CheckAlarm(isAlarm, getTime);
//                                if (!isAlarm)
//                                {
//                                    derivedRealAlarm.AlarmTimeEnd = endTime;
//                                }
//                            }
//                            //主从关联告警（信源主控有离线告警，则信源主控的其它告警都关联到此告警下）
//                            else if ("5".Equals(derivedRealAlarm.relationMethod))
//                            {
//                                isAlarm = false;
//                                createAlarm = false;    //不产生新的告警，只做关联
//                                parentAlarmKey = "";
//                                foreach (RealAlarmModel realAlarm in stationAlarm.Values)
//                                {
//                                    bool tmpAlarm = (!realAlarm.isEnd && realAlarm.alarm);
//                                    if (tmpAlarm)
//                                    {
//                                        //获取需要关联的告警ID，然后判断是否告警，告警则赋值parentAlarmKey
//                                        if (realAlarm.alarmId == derivedRealAlarm.alarmId)
//                                        {
//                                            parentAlarmKey = realAlarm.alarmKey;
//                                            break;
//                                        }
//                                    }
//                                }
//                            }
//                            else
//                            {
//                                isAlarm = false;
//                            }
//                            break;
//                    }
//                }
//                else
//                {
//                    isAlarm = false;
//                }

//                //告警
//                if (isAlarm)
//                {
//                    RealAlarmModel realAlarmModel;
//                    //-1不需要更新
//                    int saveType = -1;
//                    //未包含&&包含但已结束
//                    if (stationAlarm.ContainsKey(alarmCode))
//                    {
//                        realAlarmModel = stationAlarm[alarmCode];
//                        //已经结束的，重新开启，alarmKey也重新生成
//                        if (realAlarmModel.isEnd)
//                        {
//                            //1需要更新
//                            saveType = 1;
//                            realAlarmModel.GetTime = derivedRealAlarm.AlarmTimeBgn;
//                            realAlarmModel.UpdTime = derivedRealAlarm.AlarmTimeEnd;
//                            realAlarmModel.isEnd = false;
//                            realAlarmModel.alarmKey = Guid.NewGuid().ToString("N").ToUpper();
//                            realAlarmModel.parentAlarmKey = "";
//                            //告警发生时是否在时间表内
//                            realAlarmModel.isInTime = isInTime;
//                            realAlarmModel.inTimeAlarm = isInTime;
//                        }
//                    }
//                    else
//                    {
//                        //新增
//                        saveType = 0;
//                        realAlarmModel = new RealAlarmModel() { GetTime = derivedRealAlarm.AlarmTimeBgn, isInTime = isInTime, UpdTime = derivedRealAlarm.AlarmTimeEnd };
//                    }

//                    realAlarmModel.alarmTimeout = 0;
//                    realAlarmModel.alarmEndTimeout = 0;
//                    realAlarmModel.alarmName = derivedRealAlarm.rulerName;
//                    realAlarmModel.alarmType = derivedRealAlarm.alarmType;
//                    //realAlarmModel.alarmLevel = derivedRealAlarm.derivedAlarmLevel.ToString();
//                    realAlarmModel.alarmLevel = derivedRealAlarm.alarmLevel.ToString();
//                    realAlarmModel.alarmLevelReal = realAlarmModel.alarmLevel;
//                    realAlarmModel.alarmTitle = derivedRealAlarm.alarmTitle;
//                    realAlarmModel.alarmTitleId = derivedRealAlarm.alarmTitleId;
//                    realAlarmModel.alarmDesc = derivedRealAlarm.rulerDescribe;
//                    //realAlarmModel.isInTime = true; //告警发生时是否在时间表内
//                    //realAlarmModel.alarm = true;    //是否推送告警
//                    realAlarmModel.alarm = isInTime;    //是否推送告警
//                    //realAlarmModel.inTimeAlarm = true;    //就是开始或结束时间在播出时间内，或者持续时间曾经在播出时间告警过
//                    realAlarmModel.inTimeAlarm = realAlarmModel.inTimeAlarm || isInTime;    //就是开始或结束时间在播出时间内，或者持续时间曾经在播出时间告警过
//                    realAlarmModel.alarmCode = alarmCode;
//                    realAlarmModel.clear = false;
//                    realAlarmModel.alarmId = derivedRealAlarm.alarmId;
//                    realAlarmModel.subSysId = derivedRealAlarm.subSysId;
//                    realAlarmModel.devTypeId = derivedRealAlarm.devTypeId;
//                    realAlarmModel.onceStationAlarm = onceStationAlarm;
//                    realAlarmModel.onceFreqAlarm = false;

//                    /*************返回给前台的明细数据*********************************/
//                    realAlarmModel.CheckAlarmInfo();
//                    realAlarmModel.alarmInfo["alarm_key"] = realAlarmModel.alarmKey;                //告警ID
//                    realAlarmModel.alarmInfo["parentAlarm_key"] = realAlarmModel.parentAlarmKey;    //告警父级ID
//                    realAlarmModel.alarmInfo["alarmCode"] = realAlarmModel.alarmCode;               //告警唯一key
//                    realAlarmModel.alarmInfo["alarm_name"] = realAlarmModel.alarmName;              //告警名称
//                    realAlarmModel.alarmInfo["alarm_title"] = realAlarmModel.alarmTitle;            //告警标题
//                    realAlarmModel.alarmInfo["alarm_title_id"] = realAlarmModel.alarmTitleId;       //告警标题id
//                    realAlarmModel.alarmInfo["alarm_desc"] = realAlarmModel.alarmDesc;              //告警值描述
//                    realAlarmModel.alarmInfo["alarm_level"] = realAlarmModel.alarmLevel;            //告警级别
//                    realAlarmModel.alarmInfo["real_level"] = realAlarmModel.alarmLevelReal;         //告警级别 当前实际
//                    realAlarmModel.alarmInfo["alarm_value"] = "1";                                  //告警值 即该告警字段当前的值
//                    realAlarmModel.alarmInfo["get_time"] = TransForm.DateTimeFormat(realAlarmModel.GetTime);  //告警时间

//                    realAlarmModel.alarmInfo["isEnd"] = realAlarmModel.isEnd.ToString();            //告警是否结束
//                    realAlarmModel.alarmInfo["isInTime"] = realAlarmModel.isInTime.ToString();      //告警发生时是否在时间表内
//                    realAlarmModel.alarmInfo["alarm"] = realAlarmModel.alarm.ToString();            //是否推送告警
//                    realAlarmModel.alarmInfo["isUpdate"] = realAlarmModel.isUpdate.ToString();      //是否更新条目
//                    realAlarmModel.alarmInfo["clear"] = false.ToString();                           //是否告警清除
//                    realAlarmModel.alarmInfo["end_time"] = "";                                      //告警结束时间

//                    //realAlarmModel.alarmInfo["loopAlarm"] = realAlarmModel.loopAlarm.ToString();    //固定月末（循环）停播标识
//                    realAlarmModel.alarmInfo["onceStationAlarm"] = onceStationAlarm.ToString();     //动态（参数录入）停播标识，用于台站因各种原因随时可能产生的停播
//                    realAlarmModel.alarmInfo["onceFreqAlarm"] = false.ToString();    //动态（参数录入）停播标识，用于频率因各种原因随时可能产生的停播

//                    realAlarmModel.alarmInfo["send_status"] = "未派单";                             //派单状态
//                    //派单状态改变时
//                    if (sheetInfo.Count > 0 && sheetInfo.ContainsKey(realAlarmModel.alarmCode) && realAlarmModel.alarmKey.Equals(sheetInfo[realAlarmModel.alarmCode]))
//                    {
//                        realAlarmModel.alarmInfo["send_status"] = "已派单";
//                    }

//                    realAlarmModel.alarmInfo["dept_id"] = stationInfo.ContainsKey("dept_id") ? stationInfo["dept_id"] : "";         //维护部编码
//                    realAlarmModel.alarmInfo["dept_name"] = stationInfo.ContainsKey("dept_name") ? stationInfo["dept_name"] : "";   //维护部名称

//                    realAlarmModel.alarmInfo["alarm_id"] = realAlarmModel.alarmId.ToString();       //alarm_basic_info表id，即告警编号
//                    realAlarmModel.alarmInfo["alarm_type"] = realAlarmModel.alarmType;              //告警类型
//                    realAlarmModel.alarmInfo["station_id"] = stationId;                             //台站编号
//                    realAlarmModel.alarmInfo["station_name"] = stationInfo["station_name"];         //台站名称
//                    realAlarmModel.alarmInfo["subcenter_id"] = stationInfo["subcenter_id"];         //分中心ID
//                    realAlarmModel.alarmInfo["subcenter_name"] = stationInfo["subcenter_name"];     //分中心名称
//                    realAlarmModel.alarmInfo["station_level"] = stationLevel;                       //台站级别
//                    realAlarmModel.alarmInfo["position_id"] = "";                                   //工位号
//                    realAlarmModel.alarmInfo["frequency"] = "";                                     //频率
//                    realAlarmModel.alarmInfo["sub_system_id"] = realAlarmModel.subSysId;            //子系统编号
//                    realAlarmModel.alarmInfo["sub_system"] = derivedRealAlarm.sub_system;           //子系统名称
//                    realAlarmModel.alarmInfo["device_type_id"] = realAlarmModel.devTypeId;          //设备ID
//                    realAlarmModel.alarmInfo["device_type_name"] = derivedRealAlarm.devTypeName;    //设备名称
//                    realAlarmModel.alarmInfo["program_name"] = "";                                  //节目名称
//                    realAlarmModel.alarmInfo["program_summary"] = "";                               //节目类型
//                    realAlarmModel.alarmInfo["program_level"] = "";                                 //节目级别
//                    realAlarmModel.alarmInfo["device_type"] = "";                                   //设备编码
//                    //realAlarmModel.alarmInfo["cover_mode"] = "4";                                   //覆盖方式 当前有：调频-1 中波-2 地数-3 其它-4
//                    realAlarmModel.alarmInfo["cover_mode"] = "0";                                   //覆盖方式 当前有：调频-1 中波-2 地数-3 其它-4
//                    realAlarmModel.alarmInfo["alarm_locate"] = realAlarmModel.alarmInfo["device_type_name"];    //告警定位信息

//                    realAlarmModel.alarmInfo["tip_level"] = GetAlarmTipLevel(realAlarmModel, stationLevel, out int tipLevelMax).ToString();
//                    realAlarmModel.alarmInfo["tip_level_max"] = tipLevelMax.ToString();

//                    //放在最后，计算alarmInfo的哈希值，用于判断告警是否有变化
//                    string alarmHash = TransForm.StrToMD5Hash(JsonConvert.SerializeObject(realAlarmModel.alarmInfo.ToDictionary(ki => ki.Key, ki => (ki.Key.ToUpper().Equals("GET_TIME") || ki.Key.ToUpper().Equals("ALARM_HASH") || ki.Key.ToUpper().Equals("ALARM_VALUE")) ? "" : ki.Value)));
//                    //如果哈希值有变化，则需要更新saveType=1
//                    saveType = alarmHash.Equals(realAlarmModel.alarmInfo["alarm_hash"]) ? saveType : (saveType >= 0 ? saveType : 1);
//                    realAlarmModel.alarmInfo["alarm_hash"] = alarmHash;
//                    /*************返回给前台的明细数据*********************************/

//                    //alarmKey相关赋值
//                    parentAlarmKey = realAlarmModel.alarmKey;
//                    //台站断连 125
//                    if (derivedRealAlarm.alarmId == 125)
//                    {
//                        //台站断连key
//                        realAlarmModel.parentAlarmKey = "";
//                    }

//                    if (stationAlarm.ContainsKey(alarmCode))
//                    {
//                        stationAlarm[alarmCode] = realAlarmModel;
//                    }
//                    else
//                    {
//                        stationAlarm.TryAdd(alarmCode, realAlarmModel);
//                    }

//                    if (!updateAlarmCodes.ContainsKey(alarmCode))
//                    {
//                        lock (updateAlarmCodes)
//                        {
//                            updateAlarmCodes.TryAdd(alarmCode, false);
//                        }
//                    }
//                    if (!updateAlarmCodes[alarmCode])
//                    {
//                        saveType = 0;
//                        updateAlarmCodes[alarmCode] = true;
//                    }

//                    //只在新增时生成
//                    if (saveType >= 0)
//                    {
//                        ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetRealAlarmSql(stationAlarm[alarmCode], saveType) } });
//                    }
//                }
//                //不告警
//                else
//                {
//                    //告警已结束
//                    if (stationAlarm.ContainsKey(alarmCode))
//                    {
//                        //派单状态改变时
//                        if (sheetInfo.Count > 0 && sheetInfo.ContainsKey(alarmCode) && stationAlarm[alarmCode].alarmKey.Equals(sheetInfo[alarmCode]))
//                        {
//                            //redis.HashDelete("alarmSheetInfo", alarmCode);
//                            redis.HashDeleteAsync("alarmSheetInfo", alarmCode);
//                        }

//                        //包含的未结束的，修改时间
//                        if (!stationAlarm[alarmCode].isEnd)
//                        {
//                            //stationAlarm[alarmCode].alarm = false;
//                            stationAlarm[alarmCode].UpdTime = derivedRealAlarm.AlarmTimeEnd <= stationAlarm[alarmCode].GetTime ? stationAlarm[alarmCode].GetTime : derivedRealAlarm.AlarmTimeEnd;
//                            stationAlarm[alarmCode].isEnd = true;
//                            stationAlarm[alarmCode].alarmInfo["isEnd"] = stationAlarm[alarmCode].isEnd.ToString();
//                            stationAlarm[alarmCode].alarmInfo["end_time"] = TransForm.DateTimeFormat(stationAlarm[alarmCode].UpdTime);

//                            ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetRealAlarmSql(stationAlarm[alarmCode], 2) } });
//                            //开始或当前在播出时间内才保存历史
//                            if (stationAlarm[alarmCode].inTimeAlarm)
//                            {
//                                ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "0" }, { "key", alarmCode }, { "sql", GetSaveAlarmSql(stationAlarm[alarmCode]) } });
//                                ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetSaveAlarmSqlDM(stationAlarm[alarmCode]) } });
//                            }
//                        }
//                        //超过一定时间移除，暂定超过6个小时
//                        //else if ((DateTime.Now - stationAlarm[alarmCode].UpdTime).TotalHours > 6)
//                        //else if ((DateTime.Now - stationAlarm[alarmCode].UpdTime).TotalHours > 2)
//                        //else if ((DateTime.Now - stationAlarm[alarmCode].changeTime).TotalHours > 2)
//                        else if ((DateTime.Now - stationAlarm[alarmCode].changeTime).TotalMinutes > 3)
//                        {
//                            //stationAlarm.Remove(alarmCode);
//                            if (stationAlarm.ContainsKey(alarmCode))
//                            {
//                                stationAlarm.Remove(alarmCode);
//                            }
//                        }
//                    }
//                }

//                //cover_mode 覆盖方式 当前有：调频-1 中波-2 地数-3 其它-4
//                //dictionary_info表 dictionary_english_name=cover_mode的
//                //默认其它
//                string coverMode = "4";

//                //普通告警的parentAlarmKey设置
//                foreach (SourceAlarmCondition sourceAlarmCondition in derivedRealAlarm.SourceAlarmConditions.Values)
//                {
//                    //foreach (int alarmId in sourceAlarmCondition.AlarmIds)
//                    foreach (int alarmId in sourceAlarmCondition.RelateAlarmIds)
//                    {
//                        Dictionary<string, RealAlarmModel> tmpStationAlarm = stationAlarm.Where(d => d.Value.alarmId == alarmId && !d.Value.isEnd && !d.Value.isRelation).ToDictionary(d => d.Key, d => d.Value);
//                        if (tmpStationAlarm != null && tmpStationAlarm.Count > 0)
//                        {
//                            foreach (RealAlarmModel realAlarm in tmpStationAlarm.Values)
//                            {
//                                //使用子告警的cover_mode
//                                coverMode = realAlarm.alarmInfo.ContainsKey("cover_mode") ? realAlarm.alarmInfo["cover_mode"] : "4";

//                                //createAlarm为true时，isAlarm不一定为true
//                                //createAlarm为false时，isAlarm一定为false
//                                //条件1：当前isAlarm时，赋值parentAlarmKey
//                                //条件2：当前非createAlarm，且parentAlarmKey非空时，说明是不产生新的告警，但是关联告警有产生，所以赋值parentAlarmKey
//                                //realAlarm.parentAlarmKey = (isAlarm || (!createAlarm && !"".Equals(parentAlarmKey))) ? parentAlarmKey :
//                                //    (derivedRealAlarm.used ? "" : realAlarm.parentAlarmKey);    //这块是判断是否used，非使用中时，使用原来的parentAlarmKey，不改变其值

//                                realAlarm.parentAlarmKey = (isAlarm || (!createAlarm && !"".Equals(parentAlarmKey))) ? parentAlarmKey : realAlarm.parentAlarmKey;
//                                realAlarm.alarmInfo["parentAlarm_key"] = realAlarm.parentAlarmKey;
//                            }
//                        }

//                        //foreach (RealAlarmModel realAlarm in stationAlarm.Values)
//                        //{
//                        //    if (!realAlarm.isEnd && realAlarm.alarmId == alarmId && !realAlarm.isRelation)
//                        //    {
//                        //        //使用子告警的cover_mode
//                        //        coverMode = realAlarm.alarmInfo.ContainsKey("cover_mode") ? realAlarm.alarmInfo["cover_mode"] : "4";

//                        //        //createAlarm为true时，isAlarm不一定为true
//                        //        //createAlarm为false时，isAlarm一定为false
//                        //        //条件1：当前isAlarm时，赋值parentAlarmKey
//                        //        //条件2：当前非createAlarm，且parentAlarmKey非空时，说明是不产生新的告警，但是关联告警有产生，所以赋值parentAlarmKey
//                        //        realAlarm.parentAlarmKey = (isAlarm || (!createAlarm && !"".Equals(parentAlarmKey))) ? parentAlarmKey :
//                        //            (derivedRealAlarm.used ? "" : realAlarm.parentAlarmKey);    //这块是判断是否used，非使用中时，使用原来的parentAlarmKey，不改变其值
//                        //        realAlarm.alarmInfo["parentAlarm_key"] = realAlarm.parentAlarmKey;
//                        //    }
//                        //}
//                    }
//                }

//                //使用子告警的cover_mode
//                //非台站断连、上报超时、ping不通，才赋值
//                if (!isStationAlarm && isAlarm && stationAlarm.ContainsKey(alarmCode))
//                {
//                    stationAlarm[alarmCode].alarmInfo["cover_mode"] = coverMode;
//                }
//            }

//            //删除可能的垃圾告警
//            foreach (string alarmCode in stationAlarm.Keys)
//            {
//                if (alarmCode.ToUpper().Contains("DERIVEDALARM") && !alarmCodesAll.ContainsKey(alarmCode))
//                {
//                    stationAlarm.Remove(alarmCode);
//                }
//            }
//        }

//        /// <summary>
//        /// 获取告警提示音提示级别
//        /// </summary>
//        /// <param name="realAlarmModel"></param>
//        /// <param name="stationLevel"></param>
//        /// <param name="tipLevelMax"></param>
//        /// <returns></returns>
//        private int GetAlarmTipLevel(RealAlarmModel realAlarmModel, string stationLevel, out int tipLevelMax)
//        {
//            int tipLevel = 0;
//            tipLevelMax = 0;
//            try
//            {
//                if (alarmSets != null && alarmSets.ContainsKey(stationLevel))
//                {
//                    if (alarmSets[stationLevel] != null && alarmSets[stationLevel].ContainsKey(realAlarmModel.alarmLevel))
//                    {
//                        if (alarmSets[stationLevel][realAlarmModel.alarmLevel] != null)
//                        {
//                            Dictionary<string, Dictionary<string, string>> tmpAlarmSet = alarmSets[stationLevel][realAlarmModel.alarmLevel];
//                            DateTime alarmTime = realAlarmModel.GetTime;
//                            DateTime dtNow = DateTime.Now;
//                            foreach (string tmpTipLevel in tmpAlarmSet.Keys)
//                            {
//                                int iTmpTipLevel = int.Parse(tmpTipLevel);
//                                int tipMinute = int.Parse(tmpAlarmSet[tmpTipLevel]["tip_minute"]);
//                                int timeOut = int.Parse(tmpAlarmSet[tmpTipLevel]["time_out"]);

//                                if (alarmTime.AddMinutes(tipMinute) <= dtNow && iTmpTipLevel >= tipLevelMax)
//                                {
//                                    tipLevelMax = iTmpTipLevel;
//                                }

//                                if (alarmTime.AddMinutes(tipMinute) <= dtNow && alarmTime.AddMinutes(tipMinute).AddSeconds(timeOut) >= dtNow)
//                                {
//                                    tipLevel = iTmpTipLevel;
//                                    tipLevelMax = iTmpTipLevel;
//                                    break;
//                                }
//                            }
//                        }
//                    }
//                }
//            }
//            catch { }

//            return tipLevel;
//        }

//        /// <summary>
//        /// 新模型用
//        /// 获得入射功率信息
//        /// </summary>
//        /// <param name="txDict"></param>
//        /// <param name="txDictTmp"></param>
//        private int GetTxIpowerModel(Dictionary<string, Dictionary<string, string>> nodeDatas,
//            Dictionary<string, string> deviceInfo,
//            Dictionary<string, Dictionary<string, string>> modelParaInfo,
//            RedisHelper redis)
//        {
//            //入射功率
//            int ipower = 0;
//            //先查找天线位
//            List<string> ipowerPara = modelParaInfo.Keys.Where(k => k.ToUpper().Equals("IPOWER")).ToList();   //找出入射功率字段
//            foreach (string para_name in ipowerPara)
//            {
//                Dictionary<string, string> paraInfo = modelParaInfo[para_name];
//                //获取值
//                string val = GetFromPositionModelDatas(nodeDatas, deviceInfo, para_name, modelParaInfo, redis);
//                if (!"".Equals(val) && TransForm.IsInt(val))
//                {
//                    ipower = int.Parse(val);
//                }
//                break;
//            }

//            return ipower;
//        }

//        /// <summary>
//        /// 新模型用
//        /// 获得天线信息
//        /// </summary>
//        /// <param name="positionId">特殊处理时用</param>
//        /// <param name="nodeDatas">基础状态数据</param>
//        /// <param name="deviceInfo">当前设备信息</param>
//        /// <param name="modelParaInfo">当前设备关联静态、动态等信息</param>
//        /// <returns></returns>
//        private Dictionary<string, bool> GetTxOnlineModel(string positionId,
//            Dictionary<string, Dictionary<string, string>> nodeDatas,
//            Dictionary<string, string> deviceInfo,
//            Dictionary<string, Dictionary<string, string>> modelParaInfo,
//            RedisHelper redis)
//        {
//            //天线在线值，默认值为1时在线
//            string onLineVal = "1";

//            //特殊处理，1~3级台站，调频300W、1000W和中波发射机，主控上报天线数据时和其他的（0不在线 1在线）不一样（0在0号主机 1在1号备机）
//            //这里根据数据中的主机号HostNo（host_no）特殊辨别一下
//            //发射机类型
//            //0x8020 1000W发射机
//            //0x8021 300W发射机
//            //0x8040 中波发射机
//            if (positionId.Contains("0x8020") ||
//                positionId.Contains("0x8021") ||
//                positionId.Contains("0x8040"))
//            {
//                //主机号 0号机，1号机
//                int hostNo = 0;

//                List<string> queryHostNoParaNames = modelParaInfo.Keys.Where(k => k.ToUpper().Contains("HOST_NO")).ToList();   //主机号HostNo
//                if (queryHostNoParaNames.Count > 0)
//                {
//                    string para_name = queryHostNoParaNames[0];
//                    Dictionary<string, string> paraInfo = modelParaInfo[para_name];
//                    string tmpHostNo = GetFromPositionModelDatas(nodeDatas, deviceInfo, para_name, modelParaInfo, redis);
//                    if (!"".Equals(hostNo) && TransForm.IsInt(tmpHostNo))
//                    {
//                        hostNo = int.Parse(tmpHostNo);
//                    }
//                }

//                //0号机，值为0是是在线
//                //1号机，值为1时是在线
//                onLineVal = hostNo.ToString();
//            }

//            //判断天线位置，得出哪个位置不用告警
//            Dictionary<string, bool> txOnline = new();
//            //先查找天线位
//            List<string> queryTx = modelParaInfo.Keys.Where(k => k.ToUpper().Contains("ANTENNA") && !k.ToUpper().Contains("ALARM")).ToList();   //找出天线位
//            foreach (string para_name in queryTx)
//            {
//                Dictionary<string, string> paraInfo = modelParaInfo[para_name];
//                //截取前缀
//                string prefix = para_name.ToUpper().Equals("FREQUENCY") || !para_name.Contains('_') ? para_name.ToUpper() : para_name[..para_name.IndexOf('_')];
//                //获取天线位
//                string val = GetFromPositionModelDatas(nodeDatas, deviceInfo, para_name, modelParaInfo, redis);
//                if ("".Equals(val))
//                {
//                    //如果没有数据上报，则默认
//                    val = "0";
//                }

//                //当是特殊台站时 特殊处理 0101310200_0x0708 南宁邕宁侧转岭发射台   蒲庙镇   0101310200  10.71.31.220
//                //1是正常，代表在线 赋值0 2、3、4为不正常，这里判断为不在线
//                txOnline.TryAdd(prefix, onLineVal.Equals(val));
//            }

//            return txOnline;
//        }

//        /// <summary>
//        /// 新结构
//        /// 找出频率
//        /// </summary>
//        /// <param name="realAlarm"></param>
//        /// <param name="nodeDatas"></param>
//        /// <returns></returns>
//        private Dictionary<string, Dictionary<string, string>> GetFrqDictModel(Dictionary<string, Dictionary<string, string>> nodeDatas,
//            Dictionary<string, string> deviceInfo,
//            Dictionary<string, Dictionary<string, string>> modelParaInfo,
//            RedisHelper redis)
//        {
//            //sub_system_id 子系统ID 只能从deviceInfo拿数据
//            //0-台站 1-信号源系统 2-调频系统 3-电视系统 4-中波系统 5-电力系统 6-辅助系统 7-环境系统 8-收测系统 9-数据网 10-传输网 11-IT网
//            string sub_system_id = deviceInfo.ContainsKey("sub_system_id") ? deviceInfo["sub_system_id"] : "";
//            string positionId = deviceInfo.ContainsKey("position_id") ? deviceInfo["position_id"] : "";

//            //先查找频率
//            //找出频率字段
//            //根据频率字段，匹配频率值
//            List<string> queryFrq = modelParaInfo.Keys.Where(k => k.ToUpper().Contains("FREQUENCY") && !k.ToUpper().EndsWith("RPOWER") && !k.ToUpper().EndsWith("IPOWER")).ToList();
//            Dictionary<string, Dictionary<string, string>> frqDict = new();
//            foreach (string para_name in queryFrq)
//            {
//                Dictionary<string, string> paraInfo = modelParaInfo[para_name];
//                //这个参数也不准确，因为频率字段通常不告警
//                //string sub_system_id = paraInfo.ContainsKey("sub_system_id") ? paraInfo["sub_system_id"] : "";

//                //截取前缀
//                string prefix = para_name.ToUpper().Equals("FREQUENCY") || !para_name.Contains('_') ? para_name.ToUpper() : para_name[..para_name.IndexOf('_')];
//                string val = paraInfo["para_value"];
//                if (!"".Equals(val))
//                {
//                    frqDict.TryAdd(prefix, new() { { "frq", val ?? "" }, { "pid", positionId } });
//                }
//                else
//                {
//                    //获取频率
//                    val = GetFromPositionModelDatas(nodeDatas, deviceInfo, para_name, modelParaInfo, redis, out string[] outParams);
//                    string rPositionId = outParams[0];
//                    //有些频率可能是乱码，这里加try
//                    if (!"".Equals(val) && TransForm.IsDecimalSign(val))
//                    {
//                        try
//                        {
//                            float f = float.Parse(val);
//                            //中波台不用除 中波系统除了用系统编号4，还用类型去匹配排除
//                            //收测系统（0x0901）不用除，收测系统的sub_system_id参数不完全准确，还要匹配收测系统工位号中的设备类型0x0901
//                            if (!"4".Equals(sub_system_id) && !"8".Equals(sub_system_id) && !positionId.Contains("0x0901_") && !rPositionId.Contains("0x0901_")
//                                && !positionId.Contains("0x0705_") && !rPositionId.Contains("0x0705_") && f > 10000)
//                            {
//                                //转成KHz 除以1000
//                                //除以1000暂时对于调频有用，数字电视应该再除以1000的
//                                f = float.Parse(val) / 1000;
//                                val = f.ToString();
//                            }

//                            //电视系统，再除以1000，然后转换成甚高频（VHF）或者特高频（UHF）频道编码
//                            //if ("3".Equals(sub_system_id))
//                            //有些没有配置sub_system_id，用设备类型判断
//                            //0x0708是村级台站数字电视
//                            if ("3".Equals(sub_system_id) || positionId.ToUpper().Contains("_0X0708_"))
//                            {
//                                //有些1~3级台站数字电视切换器发射频率的单位弄错了，由MHz填成了Hz了，而由数字电视发射机转过来的则是KHz，所以单位转换需要判断
//                                if (f > 1000)
//                                {
//                                    f /= 1000;
//                                }
//                                float fTmp = f;
//                                f = TransForm.GetDTMBChannelNo(f);

//                                //没有匹配到，会返回-1，此时赋值原f值
//                                f = "-1".Equals(f.ToString()) ? fTmp : f;
//                                val = f.ToString();
//                            }

//                            frqDict.TryAdd(prefix, new() { { "frq", val }, { "pid", rPositionId } });
//                        }
//                        catch { }
//                    }
//                }
//            }

//            return frqDict;
//        }

//        /// <summary>
//        /// 数据改为存hash，一次性把该工位号下的所有数据都读取回来
//        /// 根据告警模型，获取工位号数据
//        /// </summary>
//        /// <param name="nodeDatas"></param>
//        /// <param name="deviceInfo"></param>
//        /// <param name="paraName"></param>
//        /// <param name="paraInfos"></param>
//        /// <returns></returns>
//        private string GetFromPositionModelDatas(Dictionary<string, Dictionary<string, string>> nodeDatas, Dictionary<string, string> deviceInfo,
//            string paraName, Dictionary<string, Dictionary<string, string>> paraInfos, RedisHelper redis)
//        {
//            return GetFromPositionModelDatas(nodeDatas, deviceInfo, paraName, paraInfos, redis, out _);
//        }

//        /// <summary>
//        /// 新模型用
//        /// 数据改为存hash，一次性把该工位号下的所有数据都读取回来
//        /// 根据告警模型，获取工位号数据
//        /// </summary>
//        /// <param name="nodeDatas">缓存数据载体</param>
//        /// <param name="deviceInfo">用于获取工位号信息</param>
//        /// <param name="paraName">需要获取值的参数名称</param>
//        /// <param name="paraInfos">用于获取辅助信息</param>
//        /// <param name="outParams">
//        /// 返回输出必要关联数据
//        /// 0-获取数据的工位号
//        /// 1-获取最终数据的参数码
//        /// 2-其它描述信息
//        /// </param>
//        /// <returns></returns>
//        private string GetFromPositionModelDatas(Dictionary<string, Dictionary<string, string>> nodeDatas, Dictionary<string, string> deviceInfo,
//            string paraName, Dictionary<string, Dictionary<string, string>> paraInfos, RedisHelper redis, out string[] outParams)
//        {
//            string val = "";
//            outParams = new string[3];
//            try
//            {
//                Dictionary<string, int> isEnables = stationDevIsEnables[deviceInfo["station_id"]];
//                //当前设备key
//                string device = deviceInfo["node_name"].ToUpper() + "-" + deviceInfo["position_id"].ToUpper();
//                int isEnable = isEnables.ContainsKey(device) ? isEnables[device] : 2;

//                string positionId = deviceInfo["position_id"];
//                string rPositionId = deviceInfo["relation_position_id"];
//                string parno = (paraInfos.ContainsKey(paraName) && paraInfos[paraName].ContainsKey("parno")) ? paraInfos[paraName]["parno"].ToUpper() : paraName.ToUpper();
//                string rParno = (paraInfos.ContainsKey(paraName) && paraInfos[paraName].ContainsKey("relation_parno")) ? paraInfos[paraName]["relation_parno"].ToUpper() : paraName.ToUpper();

//                //默认优先使用relation_parno
//                bool hasRparno = !"".Equals(rParno);
//                bool hasRpositionId = !"".Equals(rPositionId);
//                string pid = hasRpositionId && hasRparno ? rPositionId : positionId;
//                string pno = hasRpositionId && hasRparno ? rParno : parno;
//                if (isEnable == 1)
//                {
//                    pid = positionId;
//                    pno = parno;
//                }

//                //最终拼成位置索引
//                //string pidx = pid + "_" + pno;
//                string pidx = pno;

//                outParams[0] = pid;
//                outParams[1] = pno;

//                //使用最终的工位号和位置索引
//                if (!"".Equals(pid) && !nodeDatas.ContainsKey(pid))
//                {
//                    nodeDatas.TryAdd(pid, redis.HashGetAllDict<string>("DATA_" + pid));
//                }
//                val = (!"".Equals(pid) && nodeDatas[pid] != null && nodeDatas[pid].ContainsKey(pidx)) ? nodeDatas[pid][pidx] : "";

//                //码流记录仪 0x1002 父节点是数字信号源
//                //数字信号源 0x0102
//                if (positionId.Contains("0x1002") && pid.Contains("0x0102"))
//                {
//                    pidx = "PROGRAM" + pno.Substring(pno.IndexOf('_'));
//                    //得到值如：CCTV-1
//                    outParams[2] = (!"".Equals(pid) && nodeDatas[pid] != null && nodeDatas[pid].ContainsKey(pidx)) ? nodeDatas[pid][pidx] : "";

//                    //20250311由于设备报过来的节目名称有时候会不对（如台站设置成CCTV-7，实际是CCTV-17），也为了告警名称的统一，新增根据sid，从缓存匹配节目名称
//                    pidx = "SID" + pno.Substring(pno.IndexOf('_'));
//                    string sid = (!"".Equals(pid) && nodeDatas[pid] != null && nodeDatas[pid].ContainsKey(pidx)) ? nodeDatas[pid][pidx] : "";
//                    if (sid2ProgramInfo != null && sid2ProgramInfo.ContainsKey(sid))
//                    {
//                        outParams[2] = sid2ProgramInfo[sid];
//                    }
//                }
//                //新远场0x0902_3
//                //单条上报，告警是有就上报，没有就不上报
//                //记录了最后一条上报的时间，格式约定为为pno+"_NEWTIME"
//                //0-未告警 1-告警 2-告警结束
//                else if (pid.EndsWith("_0x0902_3"))
//                {
//                    string pidx_newtime = pidx + "_NEWTIME";
//                    string newtimeval = (!"".Equals(pid) && nodeDatas[pid] != null && nodeDatas[pid].ContainsKey(pidx_newtime)) ? nodeDatas[pid][pidx_newtime] : "";
//                    if (newtimeval != null && !"".Equals(newtimeval) &&
//                        TransForm.IsDate(newtimeval) &&
//                        (DateTime.Now - DateTime.Parse(newtimeval)).TotalSeconds > alarmTimeout)
//                    {
//                        val = "";
//                    }
//                }
//                //数字信号源，数据上报是json数据，这里只有告警数据，告警编码根据Alarm_code来判断，如果包含，则为告警1，否则为0
//                //parno下划线最后一位是Alarm_code对应的错误码，parno去掉最后一个下划线，为list数据，判断是否包含Alarm_code得到值0或1
//                else if (pid.Contains("0x0102"))
//                {
//                    string alarmCode = pno.Split("_")[0];
//                    string parnoIdx = pno.Replace(alarmCode + "_", "");
//                    //pidx = pid + "_" + parnoIdx;
//                    pidx = parnoIdx;
//                    outParams[1] = parnoIdx;
//                    try
//                    {
//                        string combineAlarmStr = (!"".Equals(pid) && nodeDatas[pid] != null && nodeDatas[pid].ContainsKey(pidx)) ? nodeDatas[pid][pidx] : "";
//                        if (combineAlarmStr != null && !"".Equals(combineAlarmStr) && !"[]".Equals(combineAlarmStr) && combineAlarmStr.Contains('['))
//                        {
//                            List<Dictionary<string, string>> combineAlarms = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(combineAlarmStr);
//                            List<Dictionary<string, string>> matchCombineAlarms = combineAlarms.Where(l => l.ContainsKey("Alarm_code") && alarmCode.Equals(l["Alarm_code"])).ToList();
//                            if (matchCombineAlarms != null && matchCombineAlarms.Count > 0)
//                            {
//                                val = "1";
//                                //返回告警里面的Alarm_descr告警描述
//                                string Alarm_belong = matchCombineAlarms[0].ContainsKey("Alarm_belong") ? matchCombineAlarms[0]["Alarm_belong"] : "";
//                                string Alarm_from = matchCombineAlarms[0].ContainsKey("Alarm_from") ? matchCombineAlarms[0]["Alarm_from"] : "";
//                                string Alarm_descr = matchCombineAlarms[0].ContainsKey("Alarm_descr") ? matchCombineAlarms[0]["Alarm_descr"] : "";

//                                //20240617 枢纽台值班人员提出，括号里包含“信号源码流”字样容易误解，这里屏蔽
//                                Alarm_from = Alarm_from.Replace("信号源码流", "");

//                                //拼接上告警来源
//                                outParams[2] = Alarm_descr + ("".Equals(Alarm_from) ? "" : ("(" + Alarm_from + ")")) + "-" + Alarm_belong.Replace("数字频点", "频点");
//                            }
//                        }
//                    }
//                    catch { }
//                }

//            }
//            catch (Exception e)
//            {
//                mLogger.LogInformation(JsonConvert.SerializeObject(nodeDatas));
//                mLogger.LogInformation("取值异常，" + e);
//            }

//            return val ?? "";
//        }

//        /// <summary>
//        /// 尝试从数据中获取最近时间
//        /// </summary>
//        /// <param name="positionId"></param>
//        /// <param name="nodeDatas"></param>
//        /// <returns></returns>
//        private DateTime GetPositionLatestTime(string positionId, Dictionary<string, Dictionary<string, string>> nodeDatas, RedisHelper redis)
//        {
//            DateTime latestTime;
//            try
//            {
//                if (!"".Equals(positionId) && !nodeDatas.ContainsKey(positionId))
//                {
//                    nodeDatas.TryAdd(positionId, redis.HashGetAllDict<string>("DATA_" + positionId));
//                }

//                //先尝试从工位号对应数据里面获取时间，获取不到则从cache获取
//                //if (nodeDatas.ContainsKey(positionId) && nodeDatas[positionId].ContainsKey(positionId + "_LATEST_TIME") && TransForm.IsDate(nodeDatas[positionId][positionId + "_LATEST_TIME"]))
//                if (nodeDatas.ContainsKey(positionId) && nodeDatas[positionId] != null && nodeDatas[positionId].ContainsKey("LATEST_TIME") && TransForm.IsDate(nodeDatas[positionId]["LATEST_TIME"]))
//                {
//                    //latestTime = TransForm.strTodateTime(nodeDatas[positionId][positionId + "_LATEST_TIME"]);
//                    latestTime = TransForm.strTodateTime(nodeDatas[positionId]["LATEST_TIME"]);
//                }
//                else
//                {
//                    latestTime = redis.StringGet<DateTime>("newest_time_cache_" + positionId);
//                    latestTime = (latestTime == default(DateTime)) ? DateTime.Now : latestTime;
//                }
//            }
//            catch (Exception e)
//            {
//                latestTime = DateTime.Now;
//                mLogger.LogError("GetPositionLatestTime有异常，" + e);
//            }
//            return latestTime;
//        }

//        /// <summary>
//        /// 获取工位好最新schemaName，用于告警历史快速定位到采集数据
//        /// schemaName是涛思或者其他记录采集数据建表时的表名称一部分，表名称："cj_" + schemaName
//        /// </summary>
//        /// <param name="positionId"></param>
//        /// <param name="nodeDatas"></param>
//        /// <returns></returns>
//        private string GetPositionSchemaName(string positionId, Dictionary<string, Dictionary<string, string>> nodeDatas, RedisHelper redis, string parno)
//        {
//            string schemaName = "";
//            //告警字段parno，必定是auto或者alarm，不会是get或者back
//            string schemaNameKey = "SCHEMANAME_AUTO";
//            if (!"".Equals(positionId) && !nodeDatas.ContainsKey(positionId))
//            {
//                nodeDatas.TryAdd(positionId, redis.HashGetAllDict<string>("DATA_" + positionId));
//            }

//            //区分数据是主动上报还是告警
//            if (!"".Equals(parno) && nodeDatas.ContainsKey(positionId) && nodeDatas[positionId] != null && nodeDatas[positionId].ContainsKey("ALARM_PARAS"))
//            {
//                Dictionary<string, string> keyDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(nodeDatas[positionId]["ALARM_PARAS"]);
//                if (keyDict != null && keyDict.ContainsKey(parno.ToUpper()))
//                {
//                    schemaNameKey = "SCHEMANAME_ALARM";
//                }
//            }

//            if (nodeDatas.ContainsKey(schemaNameKey))
//            {
//                schemaName = nodeDatas[positionId][schemaNameKey];
//            }
//            return schemaName;
//        }

//        /// <summary>
//        /// 从源数据根据参数码，直接读取值
//        /// </summary>
//        /// <param name="positionId"></param>
//        /// <param name="parno"></param>
//        /// <param name="nodeDatas"></param>
//        /// <param name="redis"></param>
//        /// <returns></returns>
//        private string GetValFromSource(string positionId, string parno, Dictionary<string, Dictionary<string, string>> nodeDatas, RedisHelper redis)
//        {
//            string val = "";
//            if (!"".Equals(positionId) && !nodeDatas.ContainsKey(positionId))
//            {
//                nodeDatas.TryAdd(positionId, redis.HashGetAllDict<string>("DATA_" + positionId));
//            }

//            //区分数据是主动上报还是告警
//            if (!"".Equals(parno) && nodeDatas.ContainsKey(positionId) && nodeDatas[positionId].ContainsKey(parno))
//            {
//                val = nodeDatas[positionId][parno];
//            }

//            return val;
//        }

//        /// <summary>
//        /// 修正（如六路调谐器）的告警数据值
//        /// 鉴于如六路调谐器（0x0901）设备的告警信息，发生消息的机制是有告警时发生，无告警时停止发生，所以这里统一对是告警上报的数据打一个特殊的标志
//        /// </summary>
//        /// <param name="positionId"></param>
//        /// <param name="newTime"></param>
//        /// <param name="parno"></param>
//        /// <param name="value"></param>
//        /// <param name="nodeDatas"></param>
//        /// <returns></returns>
//        private string RepairParaValue(string positionId, DateTime newTime, string parno, string value, Dictionary<string, Dictionary<string, string>> nodeDatas, RedisHelper redis)
//        {
//            string val = value;
//            if (!"".Equals(positionId) && !nodeDatas.ContainsKey(positionId))
//            {
//                nodeDatas.TryAdd(positionId, redis.HashGetAllDict<string>("DATA_" + positionId));
//            }

//            //先尝试从工位号对应数据里面获取时间，获取不到则从cache获取
//            if (nodeDatas.ContainsKey(positionId) && nodeDatas[positionId].ContainsKey("ALARM_TIME") && TransForm.IsDate(nodeDatas[positionId]["ALARM_TIME"]))
//            {
//                DateTime alarmTime = TransForm.strTodateTime(nodeDatas[positionId]["ALARM_TIME"]);
//                //如果台站最新时间大于告警数据时间超过N秒，则判断并赋值
//                //if ((newTime - alarmTime).TotalSeconds > 60 && nodeDatas[positionId].ContainsKey("ALARM_PARAS"))
//                if ((newTime - alarmTime).TotalSeconds > alarmTimeout && nodeDatas[positionId].ContainsKey("ALARM_PARAS"))
//                {
//                    Dictionary<string, string> keyDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(nodeDatas[positionId]["ALARM_PARAS"]);
//                    if (keyDict != null && keyDict.ContainsKey(parno.ToUpper()))
//                    {
//                        val = "";
//                    }
//                }
//            }

//            return val;
//        }

//        /// <summary>
//        /// 告警明细生成
//        /// </summary>
//        /// <param name="stationId">台站ID</param>
//        /// <param name="stationInfo">台站信息</param>
//        /// <param name="positionId">工位号</param>
//        /// <param name="dftTime">工位号最新数据时间</param>
//        /// <param name="schemaName">采集表名称</param>
//        /// <param name="device">设备，父级节点名称+工位号</param>
//        /// <param name="dynamicParas">需要判断告警的动态参数名称</param>
//        /// <param name="modelParaInfos">静态、动态参数集合</param>
//        /// <param name="deviceInfo">station_node表节点信息</param>
//        /// <param name="stationAlarm">台站告警集合，包含历史告警</param>
//        /// <param name="realAlarmRm">前端告警移除操作记录的alarmCode集</param>
//        /// <param name="nodeDatas">redis缓存数据集</param>
//        /// <param name="stationAlarmMatchInfo">频率、位置、天线、节目等集合</param>
//        private void RealAlarmModels(string stationId, Dictionary<string, string> stationInfo, string positionId, DateTime dftTime, string device,
//            List<string> dynamicParas,
//            Dictionary<string, Dictionary<string, string>> modelParaInfos,
//            Dictionary<string, string> deviceInfo,
//            Dictionary<string, RealAlarmModel> stationAlarm,
//            Dictionary<string, bool> realAlarmRm,
//            Dictionary<string, Dictionary<string, string>> nodeDatas,
//            Dictionary<string, Dictionary<string, string>> frqToProgram,
//            StationAlarmMatchInfo stationAlarmMatchInfo,
//            Dictionary<string, string> sheetInfo,
//            Dictionary<string, bool> onceAlarms,
//            RedisHelper redis)
//        {
//            //台站是否停播
//            bool onceStationAlarm = onceAlarms.ContainsKey("station") ? onceAlarms["station"] : false;

//            //是否继续判断告警，目前不判断告警的条件
//            //1、收测系统频率无法匹配到节目，则默认该通道号不在使用中
//            //2、暂无
//            bool devUsed = true;
//            //sub_system_id 子系统ID
//            //0-台站 1-信号源系统 2-调频系统 3-电视系统 4-中波系统 5-电力系统 6-辅助系统 7-环境系统 8-收测系统 9-数据网 10-传输网 11-IT网
//            string sub_system_id = deviceInfo.ContainsKey("sub_system_id") ? deviceInfo["sub_system_id"] : "";
//            string device_type_id = deviceInfo.ContainsKey("device_type_id") ? deviceInfo["device_type_id"] : "";
//            //设立只用sub_system_id判断不准确，加上设备类型匹配
//            //六路调谐器通过这里判断哪一路可用 device_type_id<>15的才是通道
//            if (!"15".Equals(device_type_id) && positionId.Contains("_0x0901_"))
//            {
//                //设备位置对应频率
//                string frqTmp = stationAlarmMatchInfo.GetFrq(device);
//                //节目信息是否为空
//                devUsed = stationAlarmMatchInfo.GetProgramInfo(frqTmp) != null;
//            }

//            //换成此方式判断
//            Dictionary<string, int> isEnables = stationDevIsEnables[stationId];
//            //父级设备key
//            //string deviceParent = deviceInfo["parent_node_name"].ToUpper() + "-" + deviceInfo["relation_position_id"].ToUpper();
//            int isEnable = isEnables.ContainsKey(device) ? isEnables[device] : 2;
//            //int isEnableParent = isEnables.ContainsKey(deviceParent) ? isEnables[deviceParent] : 2;
//            //当前设备标记为无、父级设备为无或者无isEnable参数时，说明设备不启用
//            //if (isEnable == 0 && isEnableParent != 1)
//            //当前设备标记为无、父级设备为无时，说明设备不启用
//            //if (isEnable == 0 && (isEnableParent == 0 || (isEnableParent == 2 && "".Equals(deviceInfo["relation_position_id"]))))
//            //if (isEnable == 0 && isEnableParent != 1)
//            //if (isEnable == 0 && isEnableParent == 0)
//            if (isEnable == 0)
//            {
//                devUsed = false;
//            }

//#if DEBUG
//            //if (device.Contains("0303") || device.Contains("070A")
//            //    || deviceParent.Contains("0303") || deviceParent.Contains("070A")
//            //    || device.Contains("0302") || device.Contains("070A")
//            //    || deviceParent.Contains("0302") || deviceParent.Contains("070A"))
//            //{ }
//#endif

//            //设备使用
//            if (devUsed)
//            {
//                //静态表里面的节目名称，当无法从频率表读取时，使用该名称
//                string program_name = "";
//                List<string> programCol = modelParaInfos.Keys.Where(k => k.ToUpper().Contains("PROGRAM_NAME")).ToList();
//                if (programCol.Count > 0)
//                {
//                    program_name = modelParaInfos[programCol[0]]["para_value"];
//                }

//                //工位号对应最新时间
//                Dictionary<string, DateTime> positionTimes = new();
//                //是否继续判断，如果超时了，则不再进行后续告警判断
//                //bool loop = true;
//                //遍历动态告警字段
//                foreach (string para_name in dynamicParas)
//                {
//                    //临时值
//                    string val = "";
//                    bool timtOutPara = "time_out".Equals(para_name.ToLower());
//                    //告警字段明细
//                    Dictionary<string, string> paraInfo = modelParaInfos[para_name];
//                    //唯一key
//                    string alarmCode = device + "-" + para_name.ToUpper();

//                    //告警ID
//                    int alarm_id = int.Parse(paraInfo["alarm_id"]);
//                    int alarm_type = int.Parse(paraInfo["alarm_type"].ToString());
//                    //是否开启告警
//                    int is_open = int.Parse(paraInfo["is_open"].ToString());

//                    string rPositionId = deviceInfo["relation_position_id"];
//                    string parno = modelParaInfos[para_name].ContainsKey("parno") ? modelParaInfos[para_name]["parno"] : "";
//                    string rParno = modelParaInfos[para_name].ContainsKey("relation_parno") ? modelParaInfos[para_name]["relation_parno"] : "";
//                    //默认优先使用relation_parno
//                    bool hasRparno = !"".Equals(rParno);
//                    bool hasRpositionId = !"".Equals(rPositionId);
//                    string pid = hasRpositionId && hasRparno ? rPositionId : positionId;
//                    string pno = hasRpositionId && hasRparno ? rParno : parno;
//                    //标记为有设备时，用自身的工位号和参数码
//                    if (isEnable == 1)
//                    {
//                        pid = positionId;
//                        pno = parno;
//                    }

//                    //是否使用时间表
//                    bool isUseTimetable = "1".Equals(modelParaInfos[para_name]["is_use_timetable"]);

//                    //判断是否有特殊告警判断
//                    string modelId = modelParaInfos[para_name]["model_id"];
//                    Dictionary<string, string> specDetail = null;
//                    if (modelManagement.ContainsKey(stationId) && modelManagement[stationId].ContainsKey(modelId) &&
//                        modelManagement[stationId][modelId].ContainsKey(pid) &&
//                        modelManagement[stationId][modelId][pid].ContainsKey(para_name))
//                    {
//                        specDetail = modelManagement[stationId][modelId][pid][para_name];
//                        isUseTimetable = "1".Equals(specDetail["is_use_timetable"]);

//                        //特殊处理，是否打开告警
//                        is_open = int.Parse(specDetail["is_open"].ToString());
//                    }

//                    //alarm_id大于1才是告警 alarm_type不为0
//                    //is_open告警开关，0：不产生告警；1：产生告警并推送；2：产生告警但不推送
//                    if (alarm_id > 1 && alarm_type > 0 && is_open > 0)
//                    {
//                        //默认用工位号时间
//                        DateTime newTime = dftTime;
//                        //节目名称，可能静态字段自带了program_name，所以当作默认值
//                        string programName = program_name;
//                        //告警明细
//                        string alarmDesc = paraInfo["alarm_title"];
//                        string alarmTitle = paraInfo["alarm_title"];
//                        //截取前缀
//                        string prefix = para_name.Contains('_') ? para_name[..para_name.IndexOf('_')] : para_name;
//                        string alarmName = paraInfo["alarm_describe"];
//                        //设备名称
//                        string devTypeName = paraInfo.ContainsKey("device_type_name") ? paraInfo["device_type_name"] : "";
//                        string subSystem = paraInfo.ContainsKey("sub_system_name") ? paraInfo["sub_system_name"] : "";    //子系统名称
//                        //告警定位信息
//                        string alarm_locate = devTypeName;
//                        //string alarm_locate = subSystem;
//                        int alarmLevel = int.Parse(paraInfo["alarm_level"]);

//                        //是否告警
//                        bool isAlarm = false;
//                        //实际取出值的索引值
//                        string realParno = "";

//                        //从工位号中得到设备类型
//                        string device_type = positionId.Split('_').Length > 1 ? positionId.Split('_')[1].Replace("0X", "0x") : "";
//                        string rdevice_type = pid.Split('_').Length > 1 ? pid.Split('_')[1].Replace("0X", "0x") : "";
//                        string subSysId = paraInfo.ContainsKey("sub_system_id") ? paraInfo["sub_system_id"] : "";
//                        //台站级别
//                        string stationLevel = stationInfo["station_level"];
//                        //获取告警级别跳变规则ID
//                        string ruleId = "0";
//                        switch (stationLevel)
//                        {
//                            case "1":
//                                ruleId = paraInfo.ContainsKey("one_rules") ? paraInfo["one_rules"] : ruleId;
//                                break;
//                            case "2":
//                                ruleId = paraInfo.ContainsKey("two_rules") ? paraInfo["two_rules"] : ruleId;
//                                break;
//                            case "3":
//                                ruleId = paraInfo.ContainsKey("three_rules") ? paraInfo["three_rules"] : ruleId;
//                                break;
//                            case "4":
//                                ruleId = paraInfo.ContainsKey("four_rules") ? paraInfo["four_rules"] : ruleId;
//                                break;
//                            case "5":
//                                ruleId = paraInfo.ContainsKey("five_rules") ? paraInfo["five_rules"] : ruleId;
//                                break;
//                            default: break;
//                        }

//                        //如果是关联的，则最新的时间也取关联的时间
//                        if (!positionTimes.ContainsKey(pid))
//                        {
//                            newTime = GetPositionLatestTime(pid, nodeDatas, redis);
//                            positionTimes.TryAdd(pid, newTime);
//                        }
//                        else
//                        {
//                            newTime = positionTimes[pid];
//                        }

//                        //parno数据来源
//                        string schemaName = GetPositionSchemaName(pid, nodeDatas, redis, parno.ToUpper());

//                        //是否需要告警
//                        bool needAlarm = stationAlarmMatchInfo.GetPositionAlarm(device, prefix);
//                        //频率
//                        string frequency = stationAlarmMatchInfo.GetFrq(device, prefix);
//                        //离线告警，1~3级台站数字电视，频率取真实值
//                        if (timtOutPara && "0X0706".Equals(device_type.ToUpper()))
//                        {
//                            frequency = stationAlarmMatchInfo.GetFrqReal(device, prefix);
//                        }
//                        //数字电视切换器（主控）如果从来没有数据返回，就没有频率和节目名称信息，这里特殊处理
//                        //if ("".Equals(frequency) && "0X0706".Equals(device_type.ToUpper()))
//                        if (("".Equals(frequency) || "0".Equals(frequency)) && "0X0706".Equals(device_type.ToUpper()))
//                        {
//                            //根据工位号，转换成发射机A（主）机工位号，获取频率
//                            string dtvPositionId = stationId + "_0x0303_" + (2 * int.Parse(positionId.Split('_')[2]) - 1).ToString();
//                            frequency = stationAlarmMatchInfo.GetFrqForPositionId(dtvPositionId);
//                        }

//                        //alarm_always_show告警是否持续，默认0：关闭，1：打开（当前适用：非在播发射机未修复、1 + 1切换器与发射机通信）
//                        if (!needAlarm)
//                        {
//                            int alwaysAlarm = (paraInfo.ContainsKey("alarm_always_show") && TransForm.IsInt(paraInfo["alarm_always_show"])) ? int.Parse(paraInfo["alarm_always_show"]) : 0;
//                            //即使是需要，也要做一些基本的判断，比如另外一台发射机不存在或未启用
//                            if (alwaysAlarm == 1)
//                            {

//                                if ("0X0303".Equals(device_type.ToUpper()))
//                                {
//                                    //工位号编号
//                                    int positionNo = int.Parse(positionId.Split('_')[2]);
//                                    //是备机时，判断是否有备机，否则会造成很多误告警
//                                    if (positionNo % 2 == 0)
//                                    {
//                                        //切换器通信状态0-断连，1-正常，2-无切换器
//                                        string hasSwitch = GetValFromSource(pid, "N0X0301", nodeDatas, redis);
//                                        //是否有备机0-无，1-有
//                                        string hasSub = GetValFromSource(pid, "N0X0304", nodeDatas, redis);
//                                        //切换器通信正常，且有备机
//                                        if ("1".Equals(hasSwitch) && "1".Equals(hasSub))
//                                        {
//                                            needAlarm = true;
//                                        }
//                                    }
//                                    else
//                                    {
//                                        needAlarm = true;
//                                    }
//                                }
//                                else if ("0X8021".Equals(device_type.ToUpper()))
//                                {
//                                    needAlarm = true;
//                                }
//                                else
//                                {
//                                    needAlarm = true;
//                                }
//                            }
//                        }

//                        //20240605 1-3级台站数字电视，alarmId=163（主1）或者298（备2）为激励器输入码流告警，需要判断当前激励器是否在用，不在用的不告警
//                        //固定设置，alwaysAlarm参数也不能起作用
//                        if (needAlarm && "0X0303".Equals(device_type.ToUpper()) && (alarm_id == 163 || alarm_id == 298))
//                        {
//                            //区分0、1号机 dtvDevNo=1是0号机，否则是1号机
//                            int dtvDevNo = int.Parse(positionId.Split('_')[2]) % 2;
//                            //当前工作激励器1或2，为空则代表只有一个激励器，无法区分
//                            //string jiliCurrent = GetValFromSource(pid, alarm_id == 163 ? "N0X0802" : "N0X0803", nodeDatas, redis) ?? "";
//                            string jiliCurrent = GetValFromSource(pid, dtvDevNo == 1 ? "N0X0802" : "N0X0803", nodeDatas, redis) ?? "";
//                            //无法区分时，就直接告警
//                            //等于0时，是只有一个激励，不需要判断哪个在用，加上非0严格来判断
//                            if (!"".Equals(jiliCurrent) && !"0".Equals(jiliCurrent) &&
//                                ((alarm_id == 163 && !"1".Equals(jiliCurrent)) ||
//                                (alarm_id == 298 && !"2".Equals(jiliCurrent))))
//                            {
//                                needAlarm = false;
//                            }
//                        }

//                        //是否播出时间
//                        //isUseTimetable是否使用时间表，不适用则直接为true
//                        bool isInTime = isUseTimetable ? stationAlarmMatchInfo.GetInTime(frequency, subSysId) : true;
//                        //节目信息
//                        Dictionary<string, string> programInfo = stationAlarmMatchInfo.GetProgramInfo(frequency);
//                        //节目描述
//                        string programSummary = "";
//                        //节目级别
//                        string programLevel = "";
//                        if (programInfo != null)
//                        {
//                            programName = programInfo["program_name"];
//                            programSummary = programInfo["summary"];
//                            programLevel = programInfo["program_level"];
//                        }

//                        //判断是否关联衍生告警
//                        bool relateAlarm = paraInfo.ContainsKey("sub_para_name") && !"".Equals(paraInfo["sub_para_name"]);
//                        //关联名称
//                        string[] subParaNames = relateAlarm ? paraInfo["sub_para_name"].Split(',') : null;
//                        //判定规则，目前只有1
//                        //1-所有子告警都告警时才告警
//                        //2-只要有一个告警，就告警
//                        string ruleSymbol = (relateAlarm && paraInfo.ContainsKey("rule_symbol")) ? paraInfo["rule_symbol"] : (relateAlarm ? "1" : "");
//                        //是否关联
//                        bool isFold = (relateAlarm && paraInfo.ContainsKey("is_fold")) ? ("1".Equals(paraInfo["is_fold"])) : false;
//                        //关联的衍生告警唯一key
//                        List<string> subAlarmCodes = relateAlarm ? new() : null;

//                        //AI地数图像识别0x1003是否告警需要特殊处理
//                        //节目LATEST_TIME与当时间间隔超过10分钟（暂定），不告警
//                        //节目error_start_time（错误开始时间）与当时间间隔小于5分钟（暂定），不告警
//                        string aiProgramName = "";
//                        if ("0x1003".Equals(device_type) &&
//                            (para_name.ToLower().Contains("static_frame") ||
//                            para_name.ToLower().Contains("mosaic_rate") ||
//                            para_name.ToLower().Contains("black_burst") ||
//                            para_name.ToLower().Contains("sound_off")))
//                        {
//                            //获取最新时间和错误开始时间
//                            string latestTime = GetFromPositionModelDatas(nodeDatas, deviceInfo, prefix + "_latest_time", modelParaInfos, redis);
//                            string errStartTime = GetFromPositionModelDatas(nodeDatas, deviceInfo, prefix + "_error_start_time", modelParaInfos, redis);

//                            //节目名称也特殊
//                            aiProgramName = GetFromPositionModelDatas(nodeDatas, deviceInfo, prefix + "_program_name", modelParaInfos, redis);

//                            //根据最新时间和错误开始时间，判断是否应该告警
//                            //最新时间和当前时间间隔小于10分钟，才告警，否则不告警（needAlarm=false）
//                            if (latestTime != null && !"".Equals(latestTime) && TransForm.IsDate(latestTime))
//                            {
//                                DateTime ltTime = TransForm.strTodateTime(latestTime);
//                                if ((DateTime.Now - ltTime).TotalMinutes > AILatestMinuteGap)
//                                {
//                                    needAlarm = false;
//                                }
//                            }
//                            else
//                            {
//                                //最新时间异常，不告警
//                                needAlarm = false;
//                            }

//                            //错误开始时间和当前时间间隔大于2分钟，才告警，否则不告警（needAlarm=false）
//                            if (errStartTime != null && !"".Equals(errStartTime) && TransForm.IsDate(errStartTime))
//                            {
//                                DateTime errTime = TransForm.strTodateTime(errStartTime);
//                                //对应关系静帧、马赛克、黑场、无伴音，值分别默认为3、5、0、5
//                                int errIdx = 0;
//                                if (para_name.ToLower().Contains("static_frame"))
//                                {
//                                    errIdx = 0;
//                                }
//                                else if (para_name.ToLower().Contains("mosaic_rate"))
//                                {
//                                    errIdx = 1;
//                                }
//                                else if (para_name.ToLower().Contains("black_burst"))
//                                {
//                                    errIdx = 2;
//                                }
//                                else if (para_name.ToLower().Contains("sound_off"))
//                                {
//                                    errIdx = 3;
//                                }

//                                if (needAlarm && (DateTime.Now - errTime).TotalMinutes < AIErrStartMinuteGap[errIdx])
//                                {
//                                    needAlarm = false;
//                                }
//                            }
//                            else
//                            {
//                                needAlarm = false;
//                            }
//                        }

//                        //如果需要告警
//                        if (needAlarm)
//                        {
//                            //判断是否关联衍生告警
//                            if (relateAlarm)
//                            {
//                                bool tmpAlarm = true;
//                                int relateCount = 0;
//                                //1-所有子告警都告警时才告警
//                                if ("1".Equals(ruleSymbol))
//                                {
//                                    tmpAlarm = true;
//                                    isInTime = false;
//                                    foreach (string subParaName in subParaNames)
//                                    {
//                                        //关联的唯一key
//                                        string subAlarmCode = device + "-" + subParaName.ToUpper();
//                                        subAlarmCodes.Add(subAlarmCode);
//                                        if (stationAlarm.ContainsKey(subAlarmCode))
//                                        {
//                                            //AI地数图像识别 0x1003 曲线方式获取频率信息
//                                            if (("0x1003".Equals(device_type) || "0x1002".Equals(device_type)) && "".Equals(frequency) && !stationAlarm[subAlarmCode].isEnd)
//                                            {
//                                                frequency = stationAlarm[subAlarmCode].alarmInfo["frequency"];
//                                                programName = stationAlarm[subAlarmCode].alarmInfo["program_name"];
//                                                programSummary = stationAlarm[subAlarmCode].alarmInfo["program_summary"];
//                                                programLevel = stationAlarm[subAlarmCode].alarmInfo["program_level"];
//                                            }

//                                            if (!!stationAlarm[subAlarmCode].isEnd)
//                                            {
//                                                isInTime = (isInTime || stationAlarm[subAlarmCode].alarm);
//                                            }

//                                            tmpAlarm = (tmpAlarm && !stationAlarm[subAlarmCode].isEnd);
//                                            relateCount++;
//                                        }
//                                    }
//                                    //告警时值为1，否则不为1，让关联衍生告警走后续普通告警流程
//                                    val = (tmpAlarm && relateCount == subParaNames.Length) ? "1" : "0";
//                                }
//                                //2-只要有一个告警，就告警
//                                else if ("2".Equals(ruleSymbol))
//                                {
//                                    tmpAlarm = false;
//                                    isInTime = false;
//                                    foreach (string subParaName in subParaNames)
//                                    {
//                                        //关联的唯一key
//                                        string subAlarmCode = device + "-" + subParaName.ToUpper();
//                                        //只要有一个告警，就告警
//                                        if (stationAlarm.ContainsKey(subAlarmCode) && !stationAlarm[subAlarmCode].isEnd)
//                                        {
//                                            //AI地数图像识别 0x1003 曲线方式获取频率信息
//                                            if (("0x1003".Equals(device_type) || "0x1002".Equals(device_type)) && "".Equals(frequency))
//                                            {
//                                                frequency = stationAlarm[subAlarmCode].alarmInfo["frequency"];
//                                                programName = stationAlarm[subAlarmCode].alarmInfo["program_name"];
//                                                programSummary = stationAlarm[subAlarmCode].alarmInfo["program_summary"];
//                                                programLevel = stationAlarm[subAlarmCode].alarmInfo["program_level"];
//                                            }

//                                            isInTime = (isInTime || stationAlarm[subAlarmCode].alarm);

//                                            subAlarmCodes.Add(subAlarmCode);
//                                            tmpAlarm = true;
//                                            relateCount++;
//                                        }
//                                    }
//                                    //告警时值为1，否则不为1，让关联衍生告警走后续普通告警流程
//                                    val = (tmpAlarm && relateCount > 0) ? "1" : "0";
//                                }
//                                else
//                                {
//                                    //其他方式暂无
//                                    val = "0";
//                                }
//                            }
//                            //超时time_out，单独判断
//                            else if (timtOutPara)
//                            {
//                                //设备是否离线
//                                val = GetPositionOffLine(pid, redis);
//                                alarmName = pid;

//                                //特殊获取节目相关信息
//                                //AI地数图像识别 0x1003
//                                //地数信号源 0x0102
//                                if ("0x1003".Equals(device_type) || "0x0102".Equals(device_type))
//                                {
//                                    //Dictionary<string, Dictionary<string, string>> matchProgram = frqToProgram.Where(p => p.Value["summary"].Equals("数字电视")).ToDictionary(d => d.Key, d => d.Value);
//                                    Dictionary<string, Dictionary<string, string>> matchProgram = frqToProgram.Where(p => p.Value["summary"].StartsWith("数字电视") || p.Value["program_name"].StartsWith("数字电视")).ToDictionary(d => d.Key, d => d.Value);
//                                    if (matchProgram != null && matchProgram.Count > 0)
//                                    {
//                                        string tmpFrequency = matchProgram.Keys.ToList()[0];
//                                        //频率单独获取后，再次主动关联时间表
//                                        isInTime = isUseTimetable ? stationAlarmMatchInfo.GetInTime(tmpFrequency, subSysId) : isInTime;
//                                    }
//                                }
//                            }
//                            else
//                            {
//                                //判断alarmId是否告警
//                                val = GetFromPositionModelDatas(nodeDatas, deviceInfo, para_name, modelParaInfos, redis, out string[] outParams);
//                                alarmName = outParams[0] + "_" + outParams[1];
//                                realParno = outParams[1];
//                                alarm_locate = outParams[2] ?? alarm_locate;

//                                //鉴于如六路调谐器（0x0901）设备的告警信息，发生消息的机制是有告警时发生，无告警时停止发生，所以这里对其进行特殊处理
//                                //模拟信号源软件控制器 0x0101
//                                //1-3级台站电力软件控制器 0x0B01
//                                //1-3级台站环境系统软件控制器 0x0E01
//                                //以上都是和0x0901一样的处理
//                                if (val != null && !"".Equals(val) && (
//                                    pid.Contains("_0x0901_") ||
//                                    pid.Contains("_0x0101_") ||
//                                    pid.Contains("_0x0B01_") ||
//                                    pid.Contains("_0x0E01_")
//                                    ))
//                                {
//                                    //20250303 和韦明万确认后，都是一直上报的，屏蔽此处逻辑
//                                    //val = RepairParaValue(pid, newTime, pno, val, nodeDatas, redis);
//                                }

//                                //特殊获取节目相关信息
//                                //AI地数图像识别 0x1003
//                                //地数信号源 0x0102
//                                //地数信号源-收测（码流分析仪） 0x1002
//                                if ("0x1003".Equals(device_type) || "0x0102".Equals(device_type) || "0x1002".Equals(device_type))
//                                {
//                                    if (!"".Equals(realParno) && frqToProgram.Count > 0)
//                                    {
//                                        string program_id = "";
//                                        if ("0x1003".Equals(device_type) && TransForm.IsInt(realParno[..1]))
//                                        {
//                                            //realParno的第一位从0开始，0、1、2分别对应频点1、2、3，通过program_id反向匹配节目信息
//                                            program_id = (int.Parse(realParno[..1]) + 1).ToString();
//                                        }
//                                        else if ("0x0102".Equals(device_type))
//                                        {
//                                            string[] paramArrs = realParno.Split('_');
//                                            if (paramArrs != null && paramArrs.Length > 1)
//                                            {
//                                                //根据参数格式，倒数第二位为频点
//                                                //格式样例：10202_CombineAlarm_list_1_CombineAlarm
//                                                program_id = paramArrs[paramArrs.Length - 2];
//                                            }
//                                        }
//                                        else if ("0x1002".Equals(device_type))
//                                        {
//                                            program_id = positionId.Split('_')[positionId.Split('_').Length - 1];
//                                        }

//                                        Dictionary<string, Dictionary<string, string>> matchProgram = frqToProgram.Where(p => p.Value["program_id"].Equals(program_id)).ToDictionary(d => d.Key, d => d.Value);
//                                        if (matchProgram != null && matchProgram.Count > 0)
//                                        {
//                                            frequency = matchProgram.Keys.ToList()[0];
//                                            //频率单独获取后，再次主动关联时间表
//                                            isInTime = isUseTimetable ? stationAlarmMatchInfo.GetInTime(frequency, subSysId) : isInTime;

//                                            programInfo = matchProgram[frequency];
//                                            if (programInfo != null)
//                                            {
//                                                programName = programInfo["program_name"];
//                                                programSummary = programInfo["summary"];
//                                                programLevel = programInfo["program_level"];
//                                            }
//                                        }
//                                    }
//                                }
//                            }

//                            //根据告警值及配置的参数判断是否告警
//                            //if (val != null && !"".Equals(val) && (TransForm.IsDecimalSign(val) || TransForm.IsInt(val)))
//                            if (val != null && !"".Equals(val))
//                            {
//                                //是数字时
//                                if ((TransForm.IsDecimalSign(val) || TransForm.IsInt(val)))
//                                {
//                                    float iVal = float.Parse(val);
//                                    float h0 = float.Parse(specDetail == null ? paraInfo["h0"].ToString() : specDetail["h0"]);
//                                    float l0 = float.Parse(specDetail == null ? paraInfo["l0"].ToString() : specDetail["l0"]);

//                                    //1:门限控制类别 2:0、1状态类别 3:多种状态类别
//                                    switch (alarm_type)
//                                    {
//                                        case 1:
//                                            //大于最大或小于最小值时告警
//                                            if (h0 != l0 && (iVal > h0 || iVal < l0))
//                                            {
//                                                isAlarm = true;
//                                                alarmDesc = "alarm_type:1;desc:" + l0 + "-" + h0 + ";spec=" + (specDetail != null).ToString();
//                                            }
//                                            //还是存在这种情况的，加上判断
//                                            else if (h0 == l0 && iVal != h0)
//                                            {
//                                                isAlarm = true;
//                                                alarmDesc = "alarm_type:1;desc:" + l0 + "-" + h0 + ";spec=" + (specDetail != null).ToString();
//                                            }
//                                            break;
//                                        case 2:
//                                            //等于告警值时告警
//                                            if (iVal == h0)
//                                            {
//                                                isAlarm = true;
//                                                alarmDesc = "alarm_type:2;desc:" + h0 + ";spec=" + (specDetail != null).ToString();
//                                            }
//                                            break;
//                                        case 3:
//                                            alarmDesc = "alarm_type:3;desc:" + paraInfo["alarm_describe"];
//                                            string[] descArr = paraInfo["alarm_describe"].ToString().Split(';');
//                                            foreach (string desc in descArr)
//                                            {
//                                                if (iVal == int.Parse(desc.Split(':')[0]))
//                                                {
//                                                    alarmTitle += desc.Split(':').Length > 1 ? desc.Split(':')[1] : "";
//                                                    isAlarm = true;
//                                                    break;
//                                                }
//                                            }
//                                            break;
//                                        default: break;
//                                    }
//                                }
//                                //否则就是字符串
//                                else
//                                {
//                                    string h0 = specDetail == null ? paraInfo["h0"].ToString() : specDetail["h0"];
//                                    string l0 = specDetail == null ? paraInfo["l0"].ToString() : specDetail["l0"];

//                                    //1:门限控制类别 2:0、1状态类别 3:多种状态类别
//                                    //字符串时，1类别就不处理了
//                                    switch (alarm_type)
//                                    {
//                                        case 2:
//                                            //等于告警值时告警
//                                            if (val.Equals(h0))
//                                            {
//                                                isAlarm = true;
//                                                alarmDesc = "alarm_type:2;desc:" + h0 + ";spec=" + (specDetail != null).ToString();
//                                            }
//                                            break;
//                                        case 3:
//                                            alarmDesc = "alarm_type:3;desc:" + paraInfo["alarm_describe"];
//                                            string[] descArr = paraInfo["alarm_describe"].ToString().Split(';');
//                                            foreach (string desc in descArr)
//                                            {
//                                                if (val.Equals(desc.Split(':')[0]))
//                                                {
//                                                    isAlarm = true;
//                                                    break;
//                                                }
//                                            }
//                                            break;
//                                        default: break;
//                                    }
//                                }
//                            }
//                        }

//                        //如果告警
//                        RealAlarmModel realAlarmModel;
//                        //-1不需要更新
//                        int saveType = -1;
//                        if (stationAlarm.ContainsKey(alarmCode))
//                        {
//                            realAlarmModel = stationAlarm[alarmCode];

//                            //是否告警清除，执行一次，直接将isAlarm置为false，修改clear为true即可
//                            if (realAlarmRm != null && realAlarmRm.ContainsKey(alarmCode))
//                            {
//                                realAlarmModel.clear = true;
//                                realAlarmModel.alarmInfo["clear"] = true.ToString();
//                                //realAlarmRm.Remove(alarmCode);
//                                //redis.HashSet("realAlarmRm", alarmCode, true);
//                                redis.HashSetAsync("realAlarmRm", alarmCode, true);
//                                isAlarm = false;
//                            }
//                            else
//                            {
//                                realAlarmModel.clear = false;
//                                realAlarmModel.alarmInfo["clear"] = false.ToString();
//                            }
//                        }
//                        else
//                        {
//                            //新增
//                            saveType = 0;

//                            //告警？新建RealAlarmModel
//                            realAlarmModel = isAlarm ? new RealAlarmModel { GetTime = newTime, UpdTime = newTime, isEnd = true, isInTime = isInTime, alarmLevel = alarmLevel.ToString(), alarmLevelReal = alarmLevel.ToString() } : null;
//                            if (realAlarmModel != null)
//                            {
//                                stationAlarm.TryAdd(alarmCode, realAlarmModel);
//                            }
//                        }

//                        //超时时间根据配置写入
//                        int alarmTimeout = (paraInfo.ContainsKey("alarm_show_delay") && TransForm.IsInt(paraInfo["alarm_show_delay"])) ? int.Parse(paraInfo["alarm_show_delay"]) : alarmTime;
//                        int alarmEndTimeout = (paraInfo.ContainsKey("alarm_disappear_delay") && TransForm.IsInt(paraInfo["alarm_disappear_delay"])) ? int.Parse(paraInfo["alarm_disappear_delay"]) : alarmEndTime;
//                        if (realAlarmModel != null)
//                        {
//                            realAlarmModel.alarmTimeout = alarmTimeout;
//                            realAlarmModel.alarmEndTimeout = alarmEndTimeout;
//                        }

//                        //告警判断，连续两次告警或者不告警，才算针对告警或者结束
//                        isAlarm = (realAlarmModel == null ? false : realAlarmModel.CheckAlarm(isAlarm, newTime, timtOutPara));


//                        //判断设备是否离线，如果离线，则赋值loop，后续的其他告警全部不更新
//                        if (timtOutPara && isAlarm)
//                        {
//#if DEBUG
//                            //loop = true;
//#else
//                            //loop = false;
//#endif
//                        }

//                        //告警时，写告警信息
//                        if (isAlarm)
//                        {
//                            //频率是否停播
//                            //只针对调频-2、电视-3、中波-4
//                            //bool onceFreqAlarm = ("2".Equals(subSysId) || "3".Equals(subSysId) || "4".Equals(subSysId)) ? (onceAlarms.ContainsKey(frequency) ? onceAlarms[frequency] : false) : false;
//                            //新增信源-1、收测-8
//                            bool onceFreqAlarm = ("2".Equals(subSysId) || "3".Equals(subSysId) || "4".Equals(subSysId) || "1".Equals(subSysId) || "8".Equals(subSysId)) ? (onceAlarms.ContainsKey(frequency) ? onceAlarms[frequency] : false) : false;

//                            //当前是否停播
//                            bool loopAlarm = false;
//                            //停播类型，0不停，1倒数第一个周二，2倒数第二个周二
//                            int loopAlarmType = 0;
//                            //是否启用停播
//                            bool loopAlarmFlag = false;
//                            if (programInfo != null)
//                            {
//                                loopAlarmType = int.Parse(programInfo.ContainsKey("offMacRepairTime") ? programInfo["offMacRepairTime"] : "0");
//                                //最后关联上是否使用时间表字段
//                                loopAlarm = isUseTimetable ? GetLoopAlarm(subSysId, loopAlarmType, out loopAlarmFlag) : false;
//                            }

//                            //已经结束的，重新开启，alarmKey也重新生成
//                            if (realAlarmModel.isEnd)
//                            {
//                                //1需要更新
//                                saveType = 1;

//                                realAlarmModel.isEnd = false;
//                                realAlarmModel.alarmKey = Guid.NewGuid().ToString("N").ToUpper();
//                                realAlarmModel.parentAlarmKey = "";
//                                //告警发生时是否在时间表内
//                                realAlarmModel.isInTime = isInTime;
//                                realAlarmModel.inTimeAlarm = isInTime;

//                                //告警重新生成时时，实际级别和初始级别一致
//                                realAlarmModel.alarmLevelReal = alarmLevel.ToString();
//                                realAlarmModel.alarmChanges.Clear();
//                            }

//                            realAlarmModel.alarmName = alarmName;
//                            realAlarmModel.alarmType = alarm_type.ToString();
//                            //realAlarmModel.alarmTitle = paraInfo["alarm_title"];
//                            realAlarmModel.alarmTitle = alarmTitle;
//                            realAlarmModel.alarmTitleId = paraInfo["alarm_title_id"];
//                            realAlarmModel.alarmDesc = alarmDesc;
//                            realAlarmModel.clear = false;
//                            realAlarmModel.isRelation = false;
//                            realAlarmModel.isOpen = is_open;
//                            realAlarmModel.alarmId = alarm_id;
//                            realAlarmModel.alarmCode = alarmCode;
//                            realAlarmModel.subSysId = subSysId;
//                            realAlarmModel.devTypeId = paraInfo.ContainsKey("device_type_id") ? paraInfo["device_type_id"] : "";
//                            realAlarmModel.ruleId = ruleId;

//                            //告警级别
//                            realAlarmModel.alarmLevel = alarmLevel.ToString();
//                            //万一告警级别有调整，真实告警级别也跟着调整
//                            if (!alarmLevel.ToString().Equals(realAlarmModel.alarmLevel))
//                            {
//                                realAlarmModel.alarmLevelReal = alarmLevel.ToString();
//                                realAlarmModel.alarmChanges.Clear();
//                            }
//                            //避免第一次修改时发生异常，这里判断一下
//                            if ("0".Equals(realAlarmModel.alarmLevelReal) && !realAlarmModel.alarmLevelReal.Equals(realAlarmModel.alarmLevel))
//                            {
//                                realAlarmModel.alarmLevelReal = alarmLevel.ToString();
//                                realAlarmModel.alarmChanges.Clear();
//                            }

//                            if (ruleId != null && !"".Equals(ruleId) && TransForm.IsInt(ruleId) && alarmRuleInfos.ContainsKey(ruleId) && alarmLevel > 1)
//                            {
//                                AlarmRules alarmRules = alarmRuleInfos[ruleId];
//                                string levelPre = realAlarmModel.alarmLevelReal;
//                                string levelNow = (int.Parse(realAlarmModel.alarmLevelReal) - 1).ToString();
//                                DateTime dtNow = DateTime.Now;
//                                DateTime startTime = realAlarmModel.alarmChanges.ContainsKey(levelPre) ? realAlarmModel.alarmChanges[levelPre] : realAlarmModel.GetTime;
//                                int minutes = alarmRules.GetAddTime(int.Parse(realAlarmModel.alarmLevelReal));
//                                if (minutes > 0 && (dtNow - startTime).TotalMinutes > minutes)
//                                {
//                                    if (realAlarmModel.alarmChanges.ContainsKey(levelNow))
//                                    {
//                                        realAlarmModel.alarmChanges[levelNow] = dtNow;
//                                    }
//                                    else
//                                    {
//                                        realAlarmModel.alarmChanges.TryAdd(levelNow, dtNow);
//                                    }
//                                    realAlarmModel.alarmLevelReal = levelNow;
//                                }
//                            }
//                            else
//                            {
//                                realAlarmModel.alarmLevelReal = alarmLevel.ToString();
//                                realAlarmModel.alarmChanges.Clear();
//                            }

//                            //实时是否需要报送告警到前台 直接判断是否在时间表内，在则告警
//                            //此处时实时是否在时间表内
//                            realAlarmModel.alarm = isInTime;
//                            realAlarmModel.inTimeAlarm = realAlarmModel.inTimeAlarm || isInTime;    //就是开始或结束时间在播出时间内，或者持续时间曾经在播出时间告警过

//                            realAlarmModel.onceStationAlarm = onceStationAlarm;
//                            realAlarmModel.onceFreqAlarm = onceFreqAlarm;

//                            realAlarmModel.loopAlarm = loopAlarm;
//                            realAlarmModel.loopAlarmType = loopAlarmType;
//                            realAlarmModel.loopAlarmFlag = loopAlarmFlag;

//                            /*************返回给前台的明细数据*********************************/
//                            realAlarmModel.CheckAlarmInfo();
//                            realAlarmModel.alarmInfo["alarm_key"] = realAlarmModel.alarmKey;                //告警ID
//                            realAlarmModel.alarmInfo["parentAlarm_key"] = realAlarmModel.parentAlarmKey;    //告警父级ID
//                            realAlarmModel.alarmInfo["alarmCode"] = realAlarmModel.alarmCode;               //告警唯一key
//                            realAlarmModel.alarmInfo["alarm_name"] = realAlarmModel.alarmName;              //告警名称
//                            realAlarmModel.alarmInfo["alarm_title"] = realAlarmModel.alarmTitle;            //告警标题
//                            realAlarmModel.alarmInfo["alarm_title_id"] = realAlarmModel.alarmTitleId;       //告警标题id
//                            realAlarmModel.alarmInfo["alarm_desc"] = realAlarmModel.alarmDesc;              //告警值描述
//                            realAlarmModel.alarmInfo["alarm_level"] = realAlarmModel.alarmLevel;            //告警级别
//                            realAlarmModel.alarmInfo["real_level"] = realAlarmModel.alarmLevelReal;         //告警级别 当前实际
//                            realAlarmModel.alarmInfo["alarm_value"] = val;                                  //告警值 即该告警字段当前的值
//                            realAlarmModel.alarmInfo["get_time"] = TransForm.DateTimeFormat(realAlarmModel.GetTime);  //告警时间

//                            realAlarmModel.alarmInfo["isEnd"] = realAlarmModel.isEnd.ToString();            //告警是否结束
//                            realAlarmModel.alarmInfo["isInTime"] = realAlarmModel.isInTime.ToString();      //告警发生时是否在时间表内
//                            realAlarmModel.alarmInfo["alarm"] = realAlarmModel.alarm.ToString();            //是否推送告警
//                            realAlarmModel.alarmInfo["isUpdate"] = realAlarmModel.isUpdate.ToString();      //是否更新条目
//                            realAlarmModel.alarmInfo["clear"] = false.ToString();                           //是否告警清除
//                            realAlarmModel.alarmInfo["end_time"] = "";                                      //告警结束时间

//                            realAlarmModel.alarmInfo["loopAlarm"] = realAlarmModel.loopAlarm.ToString();    //固定月末（循环）停播标识
//                            realAlarmModel.alarmInfo["onceStationAlarm"] = onceStationAlarm.ToString();     //动态（参数录入）停播标识，用于台站因各种原因随时可能产生的停播
//                            realAlarmModel.alarmInfo["onceFreqAlarm"] = onceFreqAlarm.ToString();    //动态（参数录入）停播标识，用于频率因各种原因随时可能产生的停播
//                            realAlarmModel.alarmInfo["loopAlarm"] = realAlarmModel.loopAlarm.ToString();    //月末倒数第一、二个周二时有效

//                            realAlarmModel.alarmInfo["send_status"] = "未派单";                             //派单状态
//                            //派单状态改变时
//                            if (sheetInfo.Count > 0 && sheetInfo.ContainsKey(realAlarmModel.alarmCode) && realAlarmModel.alarmKey.Equals(sheetInfo[realAlarmModel.alarmCode]))
//                            {
//                                realAlarmModel.alarmInfo["send_status"] = "已派单";
//                            }


//                            realAlarmModel.alarmInfo["dept_id"] = stationInfo.ContainsKey("dept_id") ? stationInfo["dept_id"] : "";         //维护部编码
//                            realAlarmModel.alarmInfo["dept_name"] = stationInfo.ContainsKey("dept_name") ? stationInfo["dept_name"] : "";   //维护部名称

//                            realAlarmModel.alarmInfo["alarm_id"] = alarm_id.ToString();                     //alarm_basic_info表id，即告警编号
//                            realAlarmModel.alarmInfo["alarm_type"] = realAlarmModel.alarmType;              //告警类型
//                            realAlarmModel.alarmInfo["station_id"] = stationId;                             //台站编号
//                            realAlarmModel.alarmInfo["station_name"] = stationInfo["station_name"];         //台站名称
//                            realAlarmModel.alarmInfo["subcenter_id"] = stationInfo["subcenter_id"];         //分中心ID
//                            realAlarmModel.alarmInfo["subcenter_name"] = stationInfo["subcenter_name"];     //分中心名称
//                            realAlarmModel.alarmInfo["station_level"] = stationLevel;                       //台站级别
//                            realAlarmModel.alarmInfo["position_id"] = positionId;                           //工位号
//                            realAlarmModel.alarmInfo["rposition_id"] = pid;                                  //关联工位号
//                            realAlarmModel.alarmInfo["frequency"] = frequency;                              //频率
//                            realAlarmModel.alarmInfo["sub_system_id"] = realAlarmModel.subSysId;            //子系统编号
//                            realAlarmModel.alarmInfo["sub_system"] = subSystem;                            //子系统名称
//                            realAlarmModel.alarmInfo["device_type_id"] = realAlarmModel.devTypeId;          //设备ID
//                            realAlarmModel.alarmInfo["device_type_name"] = devTypeName;                     //设备名称
//                            realAlarmModel.alarmInfo["program_name"] = programName;                         //节目名称
//                            realAlarmModel.alarmInfo["program_summary"] = programSummary;                   //节目类型
//                            realAlarmModel.alarmInfo["program_level"] = programLevel;                       //节目级别
//                            realAlarmModel.alarmInfo["device_type"] = device_type;                          //设备编码  
//                            realAlarmModel.alarmInfo["rdevice_type"] = rdevice_type;                          //关联设备编码  

//                            realAlarmModel.alarmInfo["schemaName"] = schemaName;                            //采集表名称  
//                            realAlarmModel.alarmInfo["parno"] = realParno;                                  //告警字段采集表匹配名称  
//                            realAlarmModel.alarmInfo["parno_alias"] = para_name.ToLower();                  //真实采集字段名称的别名，即前端使用的名称

//                            realAlarmModel.alarmInfo["cover_mode"] = GetCoverMode(realAlarmModel);          //覆盖方式

//                            //alarm_locate默认信息为device_type_name
//                            if (alarm_locate.EndsWith("发射机"))
//                            {
//                                int dtvDevNo = int.Parse(positionId.Split('_')[2]) % 2;
//                                string pdInfo = "";

//                                //pid
//                                string parentDevType = pid.Split('_').Length > 1 ? pid.Split('_')[1].Replace("0X", "0x") : "";
//                                //1~3级台站 数字电视
//                                if ("0X0303".Equals(device_type.ToUpper()) && "0X0706".Equals(parentDevType.ToUpper()))
//                                {
//                                    pdInfo = (pid.Split('_').Length > 2 ? "频点" + pid.Split('_')[2] : "");
//                                    alarm_locate = alarm_locate + ("".Equals(pdInfo) ? "" : "-" + pdInfo) + ("".Equals(frequency) ? "" : "(" + frequency + ")-") +
//                                        (dtvDevNo == 1 ? "0" : "1") + "号机";
//                                }
//                                //乡镇数字电视 0X070A
//                                else if ("0X0302".Equals(device_type.ToUpper()))
//                                {
//                                    int pdn = (int.Parse(positionId.Split('_')[2]) + 1) / 2;
//                                    pdInfo = (pid.Split('_').Length > 2 ? "频点" + pdn : "");
//                                    alarm_locate = alarm_locate + ("".Equals(pdInfo) ? "" : "-" + pdInfo) + ("".Equals(frequency) ? "" : "(" + frequency + ")-") +
//                                        (dtvDevNo == 1 ? "0" : "1") + "号机";
//                                }
//                                //乡镇调频 0X0707为3+3切换器
//                                else if ("0X0201".Equals(device_type.ToUpper()))
//                                {
//                                    dtvDevNo = ((int.Parse(positionId.Split('_')[2]) - 1) % 6) + 1;
//                                    alarm_locate = alarm_locate + ("".Equals(pdInfo) ? "" : "-" + pdInfo) + ("".Equals(frequency) ? "" : "(" + frequency + ")-") +
//                                        (dtvDevNo < 4 ? "主机" + dtvDevNo : "备机" + (dtvDevNo - 3));
//                                }
//                                //村级台站调频 0X0709为3+1切换器，有调频1、调频2
//                                else if ("0X0709".Equals(parentDevType.ToUpper()))
//                                {
//                                    dtvDevNo = (int.Parse(positionId.Split('_')[2]) % 4);
//                                    pdInfo = (pid.Split('_').Length > 2 ? "3+1切换器" + pid.Split('_')[2] : "");
//                                    alarm_locate = pdInfo + "-" + alarm_locate + ("".Equals(frequency) ? "-" : "(" + frequency + ")-") +
//                                        (dtvDevNo > 0 ? "主机" + dtvDevNo : "备机");
//                                }
//                                //1~3级台站，中波
//                                else if ("0X0705".Equals(parentDevType.ToUpper()) || "0X0840".Equals(device_type.ToUpper()))
//                                {
//                                    alarm_locate = alarm_locate + ("".Equals(pdInfo) ? "" : "-" + pdInfo) + ("".Equals(frequency) ? "" : "(" + frequency + ")-") +
//                                        (dtvDevNo == 1 ? "0" : "1") + "号机";
//                                }
//                                //剩下的是
//                                //1~3级台站 调频 0x0701、0x0702为1+1切换器
//                                //村级台站 数字电视 0x0708为1+1切换器
//                                else
//                                {
//                                    alarm_locate = alarm_locate + ("".Equals(pdInfo) ? "" : "-" + pdInfo) + ("".Equals(frequency) ? "" : "(" + frequency + ")-") +
//                                        (dtvDevNo == 1 ? "0" : "1") + "号机";
//                                }
//                            }
//                            //1~3级台站 数字电视切换器1+1设备离线特殊处理
//                            //else if (timtOutPara && "0X0706".Equals(device_type.ToUpper()))
//                            //{
//                            //    alarm_locate += (positionId.Split('_').Length > 2 ? ("-频点" + positionId.Split('_')[2] + ("".Equals(frequency) ? "" : "(" + frequency + ")")) : "");
//                            //}
//                            //1~3级台站 数字电视1+1切换器
//                            else if ("0X0706".Equals(device_type.ToUpper()))
//                            {
//                                alarm_locate += (positionId.Split('_').Length > 2 ? ("-频点" + positionId.Split('_')[2] + ("".Equals(frequency) ? "" : "(" + frequency + ")")) : "");
//                            }
//                            //1~3级台站 数字电视收测
//                            else if ("0x0102".Equals(device_type))
//                            {
//                                //频点信息在前面已经赋予
//                                //加上频率
//                                alarm_locate += ("".Equals(frequency) ? "" : "(" + frequency + ")");
//                            }
//                            //地数信号源-收测（码流分析仪） 0x1002
//                            else if ("0x1002".Equals(device_type))
//                            {
//                                string pdNo = (positionId.Split('_').Length > 2 ? positionId.Split('_')[2] : "");
//                                //加上频率
//                                alarm_locate = ("".Equals(devTypeName) ? "" : devTypeName + "-") + "频点" + pdNo + ("".Equals(frequency) ? "" : "(" + frequency + ")") + (alarm_locate.Equals(devTypeName) ? "" : "-" + alarm_locate);
//                            }
//                            else if ("0x0101".Equals(device_type))
//                            {
//                                //频点信息在前面已经赋予
//                                //加上频率
//                                alarm_locate += ("".Equals(frequency) ? "" : "(" + frequency + ")");
//                            }

//                            /*
//                            //改为用编码来判断
//                            //else if (alarm_locate.Contains("切换器") || alarm_locate.Contains("中波"))
//                            //改名前
//                            //1   8路IP解码器
//                            //2   3 + 1切换器
//                            //3   1 + 1切换器
//                            //4   台站
//                            //5   调频发射机
//                            //6   数字电视发射机
//                            //7   4级电力复位器
//                            //8   环境软件控制器
//                            //10  主备切换器
//                            //11  中波发射机
//                            //15  模拟调谐器
//                            //16  电力软件控制器
//                            //17  发射机房
//                            //18  电力机房
//                            //19  中波控制器
//                            //20  信号源切换器
//                            //21  流媒体服务器
//                            //22  近场收测DTMB
//                            //23  远场收测DTMB
//                            //24  4级近场收测DTMB
//                            //25  数字信号源软件控制器
//                            //26  数字电视主控
//                            //27  信号源主控

//                            //改名后
//                            //1   8路IP解码器
//                            //2   3 + 1切换器
//                            //3   1 + 1切换器
//                            //4   台站
//                            //5   调频发射机
//                            //6   数字电视发射机
//                            //7   4级电力复位器
//                            //8   环境主控
//                            //10  调频主控
//                            //11  中波发射机
//                            //15  模拟调谐器
//                            //16  电力主控
//                            //17  发射机房
//                            //18  电力机房
//                            //19  中波主控
//                            //20  信号源切换器
//                            //21  AI画面识别
//                            //22  近场收测DTMB
//                            //23  远场收测DTMB
//                            //24  4级近场收测DTMB
//                            //25  数字信源主控
//                            //26  地数主控
//                            //27  信号源主控
//                            //28  码流分析仪
//                            */
//                            else if (
//                                "2".Equals(realAlarmModel.devTypeId) ||
//                                "3".Equals(realAlarmModel.devTypeId) ||
//                                "10".Equals(realAlarmModel.devTypeId) ||
//                                "11".Equals(realAlarmModel.devTypeId) ||
//                                "19".Equals(realAlarmModel.devTypeId) ||
//                                "20".Equals(realAlarmModel.devTypeId)
//                                )
//                            {
//                                //村级台站调频3+1切换器，有切换器1、2，所以再网页名称后加上切换器1或者切换器2
//                                string pdNo = (positionId.Split('_').Length > 2 ? positionId.Split('_')[2] : "");
//                                if ("0X0709".Equals(device_type.ToUpper()))
//                                {
//                                    alarm_locate += pdNo;
//                                }
//                                //乡镇数字电视 0X070A
//                                else if ("0X070A".Equals(device_type.ToUpper()))
//                                {
//                                    string pdInfo = "-频点" + pdNo;
//                                    alarm_locate += pdInfo;
//                                }
//                                //1~3级台站 数字电视 0x0706
//                                else if ("0X0706".Equals(device_type.ToUpper()))
//                                {
//                                    string pdInfo = "-频点" + pdNo;
//                                    alarm_locate += pdInfo;
//                                }

//                                //所有频率
//                                List<string> frqs = stationAlarmMatchInfo.GetFrqs(device, prefix);
//                                if (frqs.Count > 0)
//                                {
//                                    alarm_locate += "(" + String.Join(",", frqs.ToArray()) + ")";
//                                }
//                                else if (stationAlarmMatchInfo.positionIdToFrq.ContainsKey(positionId))
//                                {
//                                    alarm_locate += "(" + String.Join(",", stationAlarmMatchInfo.positionIdToFrq[positionId].Keys.ToArray()) + ")";
//                                }
//                                else if (!"".Equals(frequency))
//                                {
//                                    alarm_locate += "(" + frequency + ")";
//                                }

//                                //根据判断，主备切换器设备离线时，节目名称改为显示多个频率的节目名称，而频率字段置空
//                                //if (timtOutPara && ("主备切换器".Equals(realAlarmModel.alarmInfo["device_type_name"]) || "10".Equals(realAlarmModel.devTypeId)))
//                                //改为用只用编码判断
//                                if (timtOutPara && "10".Equals(realAlarmModel.devTypeId))
//                                {
//                                    if (frqs.Count == 0 && stationAlarmMatchInfo.positionIdToFrq.ContainsKey(positionId))
//                                    {
//                                        frqs = stationAlarmMatchInfo.positionIdToFrq[positionId].Keys.ToList();
//                                    }

//                                    if (frqs.Count > 0)
//                                    {
//                                        programName = "";
//                                        foreach (string freq in frqs)
//                                        {
//                                            //节目信息
//                                            Dictionary<string, string> tmProgramInfo = stationAlarmMatchInfo.GetProgramInfo(freq);
//                                            if (tmProgramInfo != null)
//                                            {
//                                                programName += ("".Equals(programName) ? "" : ",") + tmProgramInfo["program_name"];
//                                            }
//                                        }
//                                        realAlarmModel.alarmInfo["program_name"] = programName;
//                                    }
//                                    realAlarmModel.alarmInfo["frequency"] = "";
//                                }
//                            }

//                            //AI地数图像识别
//                            if ("0x1003".Equals(device_type))
//                            {
//                                List<string> fres = modelParaInfos.Keys.Where(k => k.ToUpper().Contains("STREAM_NAME")).ToList();
//                                if (fres != null && fres.Count > 0)
//                                {
//                                    string pinDianName = GetFromPositionModelDatas(nodeDatas, deviceInfo, fres[0], modelParaInfos, redis);
//                                    //alarm_locate += "-" + pinDianName.Replace("开路", "").Replace("-", ("".Equals(frequency) ? "-" : "(" + frequency + ")-")) + ("".Equals(aiProgramName) ? "" : "-" + aiProgramName);
//                                    //新增去掉“中央8套”等信息
//                                    alarm_locate += "-" + pinDianName.Split('-')[0].Replace("开路", "") + ("".Equals(frequency) ? "" : "(" + frequency + ")") + ("".Equals(aiProgramName) ? "" : "-" + aiProgramName);
//                                }
//                            }

//                            //realAlarmModel.alarmInfo["alarm_locate"] = alarm_locate;
//                            realAlarmModel.alarmInfo["alarm_locate"] = alarm_locate.Replace(devTypeName, subSystem);

//                            realAlarmModel.alarmInfo["tip_level"] = GetAlarmTipLevel(realAlarmModel, stationLevel, out int tipLevelMax).ToString();
//                            realAlarmModel.alarmInfo["tip_level_max"] = tipLevelMax.ToString();

//                            //放在最后，计算alarmInfo的哈希值，用于判断告警是否有变化
//                            string alarmHash = TransForm.StrToMD5Hash(JsonConvert.SerializeObject(realAlarmModel.alarmInfo.ToDictionary(ki => ki.Key, ki => (ki.Key.ToUpper().Equals("GET_TIME") || ki.Key.ToUpper().Equals("ALARM_HASH") || ki.Key.ToUpper().Equals("ALARM_VALUE")) ? "" : ki.Value)));
//                            //如果哈希值有变化，则需要更新saveType=1
//                            saveType = alarmHash.Equals(realAlarmModel.alarmInfo["alarm_hash"]) ? saveType : (saveType >= 0 ? saveType : 1);
//                            realAlarmModel.alarmInfo["alarm_hash"] = alarmHash;
//                            /*************返回给前台的明细数据*********************************/

//                            if (!updateAlarmCodes.ContainsKey(alarmCode))
//                            {
//                                lock (updateAlarmCodes)
//                                {
//                                    updateAlarmCodes.TryAdd(alarmCode, false);
//                                }
//                            }
//                            if (!updateAlarmCodes[alarmCode])
//                            {
//                                saveType = 0;
//                                updateAlarmCodes[alarmCode] = true;
//                            }

//                            if (saveType >= 0)
//                            {
//                                ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetRealAlarmSql(realAlarmModel, saveType) } });
//                            }
//                        }
//                        //未告警
//                        else
//                        {
//                            //告警已结束
//                            if (realAlarmModel != null)
//                            {
//                                //派单状态改变时
//                                if (sheetInfo.Count > 0 && sheetInfo.ContainsKey(realAlarmModel.alarmCode) && realAlarmModel.alarmKey.Equals(sheetInfo[realAlarmModel.alarmCode]))
//                                {
//                                    //redis.HashDelete("alarmSheetInfo", realAlarmModel.alarmCode);
//                                    redis.HashDeleteAsync("alarmSheetInfo", realAlarmModel.alarmCode);
//                                }

//                                //包含的未结束的，修改时间
//                                if (!realAlarmModel.isEnd)
//                                {
//                                    realAlarmModel.isEnd = true;

//                                    //AI地数图像识别，结束时，赋予结束时间时，需要判断
//                                    if ("0x1003".Equals(device_type))
//                                    {
//                                        if (realAlarmModel.GetTime == realAlarmModel.UpdTime)
//                                        {
//                                            realAlarmModel.UpdTime = DateTime.Now;
//                                        }
//                                    }

//                                    realAlarmModel.alarmInfo["isEnd"] = realAlarmModel.isEnd.ToString();
//                                    realAlarmModel.alarmInfo["end_time"] = TransForm.DateTimeFormat(realAlarmModel.UpdTime);

//                                    ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetRealAlarmSql(realAlarmModel, 2) } });
//                                    //开始或当前在播出时间内才保存历史
//                                    if (stationAlarm[alarmCode].inTimeAlarm)
//                                    {
//                                        ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "0" }, { "key", alarmCode }, { "sql", GetSaveAlarmSql(realAlarmModel) } });
//                                        ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetSaveAlarmSqlDM(realAlarmModel) } });
//                                    }
//                                }
//                                //超过一定时间移除，暂定超过6个小时
//                                //else if ((DateTime.Now - realAlarmModel.UpdTime).TotalHours > 6)
//                                //else if ((DateTime.Now - realAlarmModel.UpdTime).TotalHours > 2)
//                                //else if ((DateTime.Now - realAlarmModel.changeTime).TotalHours > 2)
//                                else if ((DateTime.Now - realAlarmModel.changeTime).TotalMinutes > 3)
//                                //else if ((DateTime.Now - realAlarmModel.UpdTime).TotalHours > 2 || !needAlarm)
//                                {
//                                    stationAlarm.Remove(alarmCode);
//                                }
//                            }
//                        }

//                        //关联衍生告警关联设置
//                        if (relateAlarm && subAlarmCodes != null && subAlarmCodes.Count > 0)
//                        {
//                            string subAlarmKey = realAlarmModel == null ? "" : (isFold ? realAlarmModel.alarmKey : "");
//                            int subMaxLevel = 10;
//                            foreach (string subAlarmCode in subAlarmCodes)
//                            {
//                                if (stationAlarm.ContainsKey(subAlarmCode) && !stationAlarm[subAlarmCode].isEnd)
//                                {
//                                    stationAlarm[subAlarmCode].isRelation = true;
//                                    stationAlarm[subAlarmCode].parentAlarmKey = isAlarm ? subAlarmKey : "";
//                                    //告警父级ID
//                                    stationAlarm[subAlarmCode].alarmInfo["parentAlarm_key"] = stationAlarm[subAlarmCode].parentAlarmKey;

//                                    /****************20250114新增动态设置哈希值，因为parentAlarmKey值变化了************************/
//                                    //修改关联后，也要重新计算哈希
//                                    //放在最后，计算alarmInfo的哈希值，用于判断告警是否有变化
//                                    string alarmHash = TransForm.StrToMD5Hash(JsonConvert.SerializeObject(stationAlarm[subAlarmCode].alarmInfo.ToDictionary(ki => ki.Key, ki => (ki.Key.ToUpper().Equals("GET_TIME") || ki.Key.ToUpper().Equals("ALARM_HASH") || ki.Key.ToUpper().Equals("ALARM_VALUE")) ? "" : ki.Value)));
//                                    stationAlarm[subAlarmCode].alarmInfo["alarm_hash"] = alarmHash;
//                                    /****************20250114新增动态设置哈希值，因为parentAlarmKey值变化了************************/

//                                    int tmpAlarmLevel = int.Parse(stationAlarm[subAlarmCode].alarmLevel);
//                                    if (tmpAlarmLevel < subMaxLevel)
//                                    {
//                                        subMaxLevel = tmpAlarmLevel;
//                                    }
//                                }
//                            }

//                            if (realAlarmModel != null)
//                            {
//                                /****************20250114新增根据子告警的级别，动态设置父类的告警级别************************/
//                                int pAlarmLevel = int.Parse(realAlarmModel.alarmLevel);
//                                if (subMaxLevel < pAlarmLevel)
//                                {
//                                    realAlarmModel.alarmLevel = subMaxLevel.ToString();
//                                    realAlarmModel.alarmInfo["alarm_level"] = realAlarmModel.alarmLevel;

//                                    //级别变了，提示级别也要跟着变
//                                    realAlarmModel.alarmInfo["tip_level"] = GetAlarmTipLevel(realAlarmModel, stationLevel, out int tipLevelMax).ToString();
//                                    realAlarmModel.alarmInfo["tip_level_max"] = tipLevelMax.ToString();

//                                    //放在最后，计算alarmInfo的哈希值，用于判断告警是否有变化
//                                    string alarmHash = TransForm.StrToMD5Hash(JsonConvert.SerializeObject(realAlarmModel.alarmInfo.ToDictionary(ki => ki.Key, ki => (ki.Key.ToUpper().Equals("GET_TIME") || ki.Key.ToUpper().Equals("ALARM_HASH") || ki.Key.ToUpper().Equals("ALARM_VALUE")) ? "" : ki.Value)));
//                                    realAlarmModel.alarmInfo["alarm_hash"] = alarmHash;
//                                }
//                                /****************20250114新增根据子告警的级别，动态设置父类的告警级别************************/
//                            }
//                        }
//                    }
//                    //else里面，用于在当数据库修改了告警信息后，可以消除已有在redis的告警
//                    else
//                    {
//                        //告警已结束
//                        if (stationAlarm.ContainsKey(alarmCode))
//                        {
//                            //包含的未结束的，修改时间
//                            if (!stationAlarm[alarmCode].isEnd)
//                            {
//                                stationAlarm[alarmCode].isEnd = true;
//                                stationAlarm[alarmCode].UpdTime = DateTime.Now;
//                                stationAlarm[alarmCode].alarmInfo["isEnd"] = stationAlarm[alarmCode].isEnd.ToString();
//                                stationAlarm[alarmCode].alarmInfo["end_time"] = TransForm.DateTimeFormat(stationAlarm[alarmCode].UpdTime);

//                                ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetRealAlarmSql(stationAlarm[alarmCode], 2) } });
//                                //开始或当前在播出时间内才保存历史
//                                if (stationAlarm[alarmCode].inTimeAlarm)
//                                {
//                                    ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "0" }, { "key", alarmCode }, { "sql", GetSaveAlarmSql(stationAlarm[alarmCode]) } });
//                                    ThreadPool.QueueUserWorkItem(new WaitCallback(PublishDatas), new Dictionary<string, string>() { { "dbtype", "1" }, { "key", alarmCode }, { "sql", GetSaveAlarmSqlDM(stationAlarm[alarmCode]) } });
//                                }
//                            }

//                            stationAlarm.Remove(alarmCode);
//                        }
//                    }
//                }
//            }
//            else
//            {
//                //处理首次新增覆盖方式，有可能升级前的覆盖方式为空的问题
//                //foreach (string para_name in dynamicParas)
//                //{
//                //    //唯一key
//                //    string alarmCode = device + "-" + para_name.ToUpper();
//                //    SetCoverMode(stationAlarm, alarmCode);
//                //}
//            }

//            //发现过有遗留数据一直未清除的情况，故而作此判断处理
//            List<string> uselessCodes;
//            //设备使用中
//            if (devUsed)
//            {
//                //有设备，则只获取不在实时告警里面的遗留数据
//                uselessCodes = stationAlarm.Keys.Where(k => k.StartsWith(device) && !k.StartsWith(stationId + "-DERIVEDALARM-") &&
//                    dynamicParas.Where(ki => k.EndsWith("-" + ki.ToUpper())).ToList().Count == 0).ToList();
//            }
//            else
//            {
//                //设备不在使用中，全部移除
//                uselessCodes = stationAlarm.Keys.Where(k => k.StartsWith(device) && !k.StartsWith(stationId + "-DERIVEDALARM-")).ToList();
//            }
//            //清除残留告警
//            ClearUselessAlarm(uselessCodes, stationAlarm);
//        }

//        /// <summary>
//        /// 获取当天是否需要告警
//        /// 判断是否月末倒数第一、第二个周末
//        /// 只对中波、调频、数字电视有效
//        /// </summary>
//        /// <param name="subSysId">子系统编号</param>
//        /// <param name="loopAlarmType">当前只有0，1，2三种状态，其中0是不启用</param>
//        /// <param name="loopAlarmFlag"></param>
//        /// <returns></returns>
//        private bool GetLoopAlarm(string subSysId, int loopAlarmType, out bool loopAlarmFlag)
//        {
//            bool loopAlarm = false;
//            loopAlarmFlag = false;
//            if (("2".Equals(subSysId) || "3".Equals(subSysId) || "4".Equals(subSysId)) && loopAlarmType > 0)
//            {
//                loopAlarmFlag = loopAlarmFlags.Length >= loopAlarmType ? '1'.Equals(loopAlarmFlags[loopAlarmType - 1]) : false;
//                //IsInTime判断是否再时间段内
//                if (loopAlarmFlag && loopAlarmTime.IsInTime(DateTime.Now))
//                {
//                    //根据数字获取当天是星期几
//                    //DayOfWeek weekday = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), "2");
//                    //loopAlarm = TransForm.IsLastWeekdayOfMonth(loopAlarmType, weekday);
//                    //默认就是周二
//                    loopAlarm = TransForm.IsLastWeekdayOfMonth(loopAlarmType);
//                }
//            }

//            return loopAlarm;
//        }

//        /// <summary>
//        /// 设置覆盖方式
//        /// </summary>
//        /// <param name="stationAlarm"></param>
//        /// <param name="alarmCode"></param>
//        private void SetCoverMode(Dictionary<string, RealAlarmModel> stationAlarm, string alarmCode)
//        {
//            if (stationAlarm.ContainsKey(alarmCode) && !stationAlarm[alarmCode].isEnd && (!stationAlarm[alarmCode].alarmInfo.ContainsKey("cover_mode") || "".Equals(stationAlarm[alarmCode].alarmInfo["cover_mode"])))
//            {
//                stationAlarm[alarmCode].alarmInfo["cover_mode"] = GetCoverMode(stationAlarm[alarmCode]);
//            }
//        }

//        /// <summary>
//        /// 获得覆盖方式
//        /// </summary>
//        /// <param name="realAlarmModel"></param>
//        /// <returns></returns>
//        private string GetCoverMode(RealAlarmModel realAlarmModel)
//        {
//            //cover_mode 覆盖方式 当前有：调频-1 中波-2 地数-3 其它-4
//            //dictionary_info表 dictionary_english_name=cover_mode的
//            //默认其它
//            string coverMode;
//            //sub_system_id=1为信号源系统
//            //sub_system_id=2为调频系统
//            //sub_system_id=3为电视系统
//            //sub_system_id=4为中波系统
//            //sub_system_id=6为辅助系统 暂无数据
//            //sub_system_id=8为收测系统
//            string devTypeName = realAlarmModel.alarmInfo["device_type_name"];
//            string device_type = realAlarmModel.alarmInfo["device_type"];
//            string frequency = realAlarmModel.alarmInfo["frequency"];
//            string programSummary = realAlarmModel.alarmInfo["program_summary"];
//            switch (realAlarmModel.subSysId)
//            {
//                case "1":
//                    //地数
//                    if (realAlarmModel.alarmCode.Contains("DTVSOURCE") || "0x0102".Equals(device_type) || programSummary.Contains("数字"))
//                    {
//                        coverMode = "3";
//                    }
//                    //中波
//                    //一定时设备类型0x0101，只要节目说明或者台站包含“中波”，即确认是中波
//                    else if ("0x0101".Equals(device_type) && (programSummary.Contains("中波") || realAlarmModel.alarmInfo["station_name"].Contains("中波") ||
//                        realAlarmModel.alarmInfo["station_name"].Contains("南宁101台")))
//                    {
//                        coverMode = "2";
//                    }
//                    //调频
//                    else if ((programSummary.Contains("调频") || (!"".Equals(frequency) && frequency.Contains('.'))) || "0x0401".Equals(device_type))
//                    {
//                        coverMode = "1";
//                    }
//                    else
//                    {
//                        coverMode = "4";
//                    }
//                    break;
//                case "2":
//                    coverMode = "1";
//                    break;
//                case "3":
//                    coverMode = "3";
//                    break;
//                case "4":
//                    coverMode = "2";
//                    break;
//                case "6":
//                    coverMode = "4";
//                    break;
//                case "8":
//                    //收测暂无告警，暂且这样分类
//                    //地数
//                    //20240925把码流分析仪归类到地数
//                    if (devTypeName.Contains("数字") || devTypeName.Contains("DTMB") ||
//                        devTypeName.Contains("流媒体") || devTypeName.Contains("1+1") ||
//                        devTypeName.Contains("码流分析仪"))
//                    {
//                        coverMode = "3";
//                    }
//                    //中波
//                    else if (devTypeName.Contains("中波") || programSummary.Contains("中波"))
//                    {
//                        coverMode = "2";
//                    }
//                    //调频
//                    else if (devTypeName.Contains("调频") || devTypeName.Contains("主备") || devTypeName.Contains("3+1") || devTypeName.Contains("解码器"))
//                    {
//                        coverMode = "1";
//                    }
//                    else
//                    {
//                        coverMode = "4";
//                    }
//                    break;
//                default:
//                    coverMode = "4";
//                    break;
//            }

//            return coverMode;
//        }
//        #endregion
//        #endregion

//        #region 辅助方法
//        /// <summary>
//        /// 生成历史告警sql
//        /// 插入涛思数据库
//        /// </summary>
//        /// <param name="realAlarmModel"></param>
//        /// <returns></returns>
//        private string GetSaveAlarmSql(RealAlarmModel realAlarmModel)
//        {
//            //ts,alarm_key,isintime,alarm,clear,get_time,upd_time,parentalarm_key,alarm_code,alarm_name,alarm_title,
//            //alarm_desc,alarm_level,alarm_value,alarm_id,alarm_type,station_id,station_name,station_level,subcenter_id,
//            //position_id,frequency,sub_system_id,device_type_id,program_name,program_summary,program_level,device_type,alarm_duration

//            //计算告警时长 单位为秒
//            TimeSpan ts = realAlarmModel.UpdTime - realAlarmModel.GetTime;
//            string positionId = realAlarmModel.alarmInfo["position_id"];
//            string stationId = realAlarmModel.alarmInfo["station_id"];
//            string alarmHisTable = alarmHisPrefix + ((positionId != null && !"".Equals(positionId)) ? positionId : stationId);

//            //StringBuilder sql = new StringBuilder();
//            //sql.Append("insert into ")
//            //    //.Append(alarmHisTableName)
//            //    //改成历史表-台站分表
//            //    .Append(alarmHisTable)
//            //    .Append("(").Append(alarmHisTableColumn).Append(") ")
//            //    .Append("values(")

//            //    .Append("'").Append(string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", DateTime.Now)).Append("',") //时间戳ts
//            //    .Append("'").Append(realAlarmModel.alarmKey).Append("',")                                       //alarm_key 告警ID
//            //    .Append(realAlarmModel.isInTime.ToString()).Append(",")                                         //isintime 是否时间表内
//            //    .Append(realAlarmModel.alarm.ToString()).Append(",")                                            //alarm 是否告警发往前台
//            //    .Append(realAlarmModel.clear.ToString()).Append(",")                                            //clear 是否手工告警清除
//            //    .Append("'").Append(string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.GetTime)).Append("',")   //get_time  告警时间
//            //    .Append("'").Append(string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.UpdTime)).Append("',")   //upd_time  告警结束时间
//            //    .Append("'").Append(realAlarmModel.parentAlarmKey).Append("',")                                 //parentalarm_key 告警父级ID
//            //    .Append("'").Append(realAlarmModel.alarmCode).Append("',")                                      //alarm_code 告警唯一编码
//            //    .Append("'").Append(realAlarmModel.alarmName).Append("',")                                      //alarm_name 告警名称
//            //    .Append("'").Append(realAlarmModel.alarmTitle).Append("',")                                     //alarm_title 告警标题

//            //    .Append("'").Append(realAlarmModel.alarmDesc).Append("',")                                      //alarmDesc 告警描述
//            //    .Append(realAlarmModel.alarmLevel).Append(",")                                                  //alarmLevel 告警级别
//            //    .Append("'").Append(realAlarmModel.alarmInfo["alarm_value"]).Append("',")                       //alarm_value 告警值
//            //    .Append(realAlarmModel.alarmInfo["alarm_id"]).Append(",")                                       //alarm_id 告警编号
//            //    .Append("".Equals(realAlarmModel.alarmInfo["alarm_type"]) ? "0" : realAlarmModel.alarmInfo["alarm_type"]).Append(",") //alarm_type 告警类型
//            //    .Append("'").Append(stationId).Append("',")                                                     //station_id 台站编号
//            //    .Append("'").Append(realAlarmModel.alarmInfo["station_name"]).Append("',")                      //station_name 台站名称
//            //    .Append(realAlarmModel.alarmInfo["station_level"]).Append(",")                                  //station_level 台站级别
//            //    .Append("'").Append(realAlarmModel.alarmInfo["subcenter_id"]).Append("',")                      //subcenter_id 分中心编号

//            //    .Append("'").Append(realAlarmModel.alarmInfo["position_id"]).Append("',")                       //position_id 工位号
//            //    .Append("'").Append(realAlarmModel.alarmInfo["frequency"]).Append("',")                         //frequency 频率
//            //    .Append("".Equals(realAlarmModel.subSysId) ? "-1" : realAlarmModel.subSysId).Append(",")        //sub_system_id 子系统编号
//            //    .Append("".Equals(realAlarmModel.devTypeId) ? "-1" : realAlarmModel.devTypeId).Append(",")      //device_type_id 设备类型编号
//            //    .Append("'").Append(realAlarmModel.alarmInfo["program_name"]).Append("',")                      //program_name 节目名称
//            //    .Append("'").Append(realAlarmModel.alarmInfo["program_summary"]).Append("',")                   //program_summary 节目类型
//            //    .Append("".Equals(realAlarmModel.alarmInfo["program_level"]) ? "-1" : realAlarmModel.alarmInfo["program_level"]).Append(",")    //program_level 节目级别
//            //    .Append("'").Append(realAlarmModel.alarmInfo["device_type"]).Append("',")                       //device_type 设备编码
//            //    .Append("'").Append(ts.TotalSeconds.ToString()).Append("',")                                    //alarm_duration 持续时长
//            //    .Append("'").Append(realAlarmModel.alarmInfo["schemaName"]).Append("',")                        //采集表名称
//            //    .Append("'").Append(realAlarmModel.alarmInfo["parno"]).Append("',")                             //告警字段采集表匹配名称
//            //    .Append("'").Append(realAlarmModel.alarmInfo["parno_alias"]).Append("',")                        //真实采集字段名称的别名，即前端使用的名称
//            //    .Append("'").Append(realAlarmModel.alarmInfo["alarm_locate"]).Append("'")                        //20231030 新增网页名称
//            //    .Append(")");
//            //return sql.ToString();

//            //改为使用GetAlarmHisInfo的数据拼接
//            Dictionary<string, string> alarmDict = realAlarmModel.GetAlarmHisInfo();
//            string sqlHis = "insert into " + alarmHisTable + "(" + String.Join(",", alarmDict.Keys.ToArray()) + ") values(" + String.Join(",", alarmDict.Values.ToArray()) + ")";
//            return sqlHis;
//        }

//        /// <summary>
//        /// 生成历史告警sql
//        /// 插入达梦数据库
//        /// </summary>
//        /// <param name="realAlarmModel"></param>
//        /// <returns></returns>
//        private string GetSaveAlarmSqlDM(RealAlarmModel realAlarmModel)
//        {
//            //改为使用GetAlarmHisInfoDM的数据拼接
//            Dictionary<string, string> alarmDict = realAlarmModel.GetAlarmHisInfoDM();
//            string tableName = "alarm_his_" + TransForm.GetFormatDatetime("yyyyMM");
//            string sqlHis = "insert into " + tableName + "(" + String.Join(",", alarmDict.Keys.ToArray()) + ") values(" + String.Join(",", alarmDict.Values.ToArray()) + ")";
//            return sqlHis;
//        }

//        /// <summary>
//        /// 生成实时告警sql
//        /// 更新pgslq的real_alarm表
//        /// </summary>
//        /// <param name="realAlarmModel"></param>
//        /// <param name="type">0：告警开始，1：告警更新，2：告警结束 3：结束掉一些因修改配置存在而无法常规更新结束的告警</param>
//        /// <returns></returns>
//        private string GetRealAlarmSql(RealAlarmModel realAlarmModel, int type, string alarmCode = "")
//        {
//            StringBuilder sql = new StringBuilder();
//            sql.Append("update real_alarm set ");
//            switch (type)
//            {
//                case 0:
//                    sql.Append(" alarm_key = '" + realAlarmModel.alarmKey + "',")
//                        .Append(" parent_alarm_key = '" + realAlarmModel.parentAlarmKey + "',")
//                        .Append(" alarm_id = " + realAlarmModel.alarmId + ",")
//                        .Append(" alarm_type = " + ("".Equals(realAlarmModel.alarmType) ? "0" : realAlarmModel.alarmType) + ",")
//                        .Append(" alarm_name = '" + realAlarmModel.alarmName + "',")
//                        .Append(" alarm_title = '" + realAlarmModel.alarmTitle + "',")
//                        .Append(" alarm_desc = '" + realAlarmModel.alarmDesc + "',")
//                        .Append(" alarm_level = " + realAlarmModel.alarmLevel + ",")
//                        .Append(" get_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.GetTime) + "',")
//                        .Append(" upd_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.UpdTime) + "',")
//                        .Append(" isend = " + realAlarmModel.isEnd.ToString() + ",")
//                        .Append(" isintime = " + realAlarmModel.isInTime.ToString() + ",")
//                        .Append(" clear = " + realAlarmModel.clear.ToString() + ",")
//                        .Append(" is_relation = " + realAlarmModel.isRelation.ToString() + ",")
//                        .Append(" is_open = " + realAlarmModel.isOpen + ",")
//                        .Append(" alarm = " + realAlarmModel.alarm.ToString() + ",")
//                        .Append(" subsys_id = " + (("".Equals(realAlarmModel.subSysId.ToString()) || TransForm.IsInt(realAlarmModel.subSysId.ToString())) ? "-1" : realAlarmModel.subSysId.ToString()) + ",")
//                        .Append(" devtype_id = " + (("".Equals(realAlarmModel.devTypeId.ToString()) || TransForm.IsInt(realAlarmModel.devTypeId.ToString())) ? "-1" : realAlarmModel.devTypeId.ToString()) + ",")
//                        .Append(" alarm_info = '" + JsonConvert.SerializeObject(realAlarmModel.alarmInfo) + "'");
//                    break;
//                case 1:
//                    sql.Append(" parent_alarm_key = '" + realAlarmModel.parentAlarmKey + "',")
//                        .Append(" get_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.GetTime) + "',")
//                        .Append(" upd_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.UpdTime) + "',")
//                        .Append(" isintime = " + realAlarmModel.isInTime.ToString() + ",")
//                        .Append(" clear = " + realAlarmModel.clear.ToString() + ",")
//                        .Append(" is_relation = " + realAlarmModel.isRelation.ToString() + ",")
//                        .Append(" is_open = " + realAlarmModel.isOpen + ",")
//                        .Append(" alarm = " + realAlarmModel.alarm.ToString() + ",")
//                        .Append(" isend = " + realAlarmModel.isEnd.ToString() + ",")
//                        .Append(" subsys_id = " + (("".Equals(realAlarmModel.subSysId.ToString()) || TransForm.IsInt(realAlarmModel.subSysId.ToString())) ? "-1" : realAlarmModel.subSysId.ToString()) + ",")
//                        .Append(" devtype_id = " + (("".Equals(realAlarmModel.devTypeId.ToString()) || TransForm.IsInt(realAlarmModel.devTypeId.ToString())) ? "-1" : realAlarmModel.devTypeId.ToString()) + ",")
//                        .Append(" alarm_info = '" + JsonConvert.SerializeObject(realAlarmModel.alarmInfo) + "'");
//                    break;
//                case 2:
//                    sql.Append(" upd_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.UpdTime) + "',")
//                        .Append(" get_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.GetTime) + "',")
//                        .Append(" isend = " + realAlarmModel.isEnd.ToString() + ",")
//                        .Append(" clear = " + realAlarmModel.clear.ToString() + ",")
//                        .Append(" is_relation = " + realAlarmModel.isRelation.ToString() + ",")
//                        .Append(" is_open = " + realAlarmModel.isOpen + ",")
//                        .Append(" subsys_id = " + (("".Equals(realAlarmModel.subSysId.ToString()) || TransForm.IsInt(realAlarmModel.subSysId.ToString())) ? "-1" : realAlarmModel.subSysId.ToString()) + ",")
//                        .Append(" devtype_id = " + (("".Equals(realAlarmModel.devTypeId.ToString()) || TransForm.IsInt(realAlarmModel.devTypeId.ToString())) ? "-1" : realAlarmModel.devTypeId.ToString()) + ",")
//                        .Append(" alarm_info = '" + JsonConvert.SerializeObject(realAlarmModel.alarmInfo) + "'");
//                    break;
//                case 3:
//                    sql.Append(" isend = " + true.ToString() + ",")
//                        .Append(" get_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.GetTime) + "',")
//                        .Append(" upd_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", DateTime.Now) + "'");
//                    break;
//                default:
//                    sql.Append(" isend = " + true.ToString() + ",")
//                        .Append(" get_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.GetTime) + "',")
//                        .Append(" upd_time = '" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", realAlarmModel.UpdTime) + "'");
//                    break;
//            }
//            sql.Append(", newest_time = now()").Append(" where alarm_code = '" + (type == 3 ? alarmCode : realAlarmModel.alarmCode) + "'");
//            return sql.ToString();
//        }
//        #endregion

//        /// <summary>
//        /// 心跳服务，定时往redis发送心跳数据
//        /// 用于获取当前服务副本数量
//        /// </summary>
//        private void HeartBeatTask()
//        {
//            //string uuid = System.Guid.NewGuid().ToString("N");
//            string uuid = nodeName;
//            string keySvr = "AlarmMergeService";   //心跳节点名称，保证唯一
//            string lockKey = "lockKeyAlarmMergeService";   //心跳节点锁key，保证唯一
//            int gapSec = 3; //循环判断间隔
//            int gapCheck = 20;   //判断时间差间隔，适当大于gapSec，如果大于，则判断为该节点离线，移除掉

//            Thread.Sleep(new Random().Next(1, (gapSec + 1)) * 1000);
//            while (true)
//            {
//                try
//                {
//                    DateTime dtNow = DateTime.Now;

//                    //更新自身节点最新时间
//                    redisInit.HashSet(keySvr, uuid, dtNow);

//                    //记录统计信息，也作为心跳数据记录的一部分
//                    nodeStatusInfo["Datetime"] = TransForm.DateTimeFormat(dtNow);
//                    nodeStatusInfo["StationNum"] = taskNum.Sum();
//                    nodeStatusInfo["LoopTime"] = loopOnceTime;
//                    nodeStatusInfo["nodeNo"] = nodeNo + 1;
//                    redisInit.HashSet("STATUS_" + keySvr, uuid, nodeStatusInfo);

//                    //判断副本数最新时间 锁过期时间为5秒
//                    redisInit.LockAndDo(lockKey, uuid, TimeSpan.FromSeconds(5),
//                        () =>
//                        {
//                            //获取key下所有节点及其时间
//                            Dictionary<string, DateTime> heartInfo = redisInit.HashGetAllDict<DateTime>(keySvr);
//                            if (heartInfo != null && heartInfo.Count > 0)
//                            {
//                                //判断节点是否超时gapCheck，超时则移除
//                                //判断当前节点ID再心跳节点的位置
//                                int idx = 0;
//                                foreach (string node in heartInfo.Keys)
//                                {
//                                    if (uuid.Equals(node))
//                                    {
//                                        //节点ID位置
//                                        nodeNo = idx;
//                                    }

//                                    //判断节点过期时间
//                                    if ((DateTime.Now - heartInfo[node]).TotalSeconds > gapCheck)
//                                    {
//                                        redisInit.HashDelete(keySvr, node);
//                                        redisInit.HashDelete("STATUS_" + keySvr, node);
//                                    }
//                                    else
//                                    {
//                                        idx++;
//                                    }
//                                }

//                                //获得节点数
//                                nodeNum = idx;
//                            }
//                            return true;
//                        });
//                }
//                finally
//                {
//                    Thread.Sleep(gapSec * 1000);
//                }
//            }
//        }

        /// <summary>
        /// 启动任务
        /// </summary>
        /// <param name="stoppingToken"></param>
        /// <returns></returns>
        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            //mLogger.LogInformation("服务已启动");

            //new Thread(TimerTask).Start();
            //new Thread(HeartBeatTask).Start();   //当前服务心跳判断

            ////new Thread(TimerAlarm).Start();
            //for (int i = 0; i < threadNum; i++)
            //{
            //    int threadNo = i;
            //    taskNum[threadNo] = 0;
            //    new Thread((ThreadStart)(delegate { TimerAlarm(threadNo); })).Start();
            //}
            //mLogger.LogInformation("处理任务数=" + threadNum);

            //new Thread(TimerInit).Start();
            return Task.CompletedTask;
        }
    }
}
